From 9bc93b1f58e2dadfb2bde69713df214256ee88ae Mon Sep 17 00:00:00 2001 From: xenomxrph Date: Thu, 14 May 2026 21:16:36 +0200 Subject: [PATCH] upload after that funky crash --- aerospace/.aerospace.toml.swp | Bin 0 -> 24576 bytes aerospace/aerospace.toml | 223 ++ ghostty/.DS_Store | Bin 0 -> 6148 bytes ghostty/config | 288 ++ ghostty/config-default | 2522 +++++++++++++++++ ghostty/ghostty-theme | 29 + ghostty/reload-config.scpt | 6 + ghostty/shaders/animated-gradient-shader.glsl | 40 + ghostty/shaders/bettercrt.glsl | 33 + ghostty/shaders/bloom.glsl | 52 + ghostty/shaders/bloom025.glsl | 52 + ghostty/shaders/bloom050.glsl | 52 + ghostty/shaders/bloom060.glsl | 52 + ghostty/shaders/bloom075.glsl | 52 + ghostty/shaders/bloom1.glsl | 52 + ghostty/shaders/crt.glsl | 310 ++ ghostty/shaders/cubes.glsl | 114 + ghostty/shaders/cursor_blaze.glsl | 117 + ghostty/shaders/cursor_blaze_no_trail.glsl | 162 ++ ghostty/shaders/cursor_smear.glsl | 117 + ghostty/shaders/cursor_smear_fade.glsl | 114 + ghostty/shaders/cursor_warp.glsl | 303 ++ ghostty/shaders/dither.glsl | 30 + ghostty/shaders/drunkard.glsl | 68 + ghostty/shaders/fireworks-rockets.glsl | 109 + ghostty/shaders/fireworks.glsl | 116 + ghostty/shaders/gears-and-belts.glsl | 377 +++ ghostty/shaders/glitchy.glsl | 117 + ghostty/shaders/glow-rgbsplit-twitchy.glsl | 144 + ghostty/shaders/gradient-background.glsl | 25 + ghostty/shaders/inside-the-matrix.glsl | 413 +++ ghostty/shaders/just-snow.glsl | 52 + ghostty/shaders/matrix-hallway.glsl | 40 + ghostty/shaders/negative.glsl | 8 + ghostty/shaders/retro-terminal.glsl | 34 + ghostty/shaders/ripple_cursor.glsl | 132 + ghostty/shaders/smoke-and-ghost.glsl | 193 ++ ghostty/shaders/sparks-from-fire.glsl | 242 ++ ghostty/shaders/spotlight.glsl | 42 + ghostty/shaders/starfield-colors.glsl | 145 + ghostty/shaders/starfield.glsl | 125 + ghostty/shaders/tft.glsl | 23 + ghostty/shaders/underwater.glsl | 74 + ghostty/shaders/water.glsl | 35 + sketchybar/.DS_Store | Bin 0 -> 6148 bytes sketchybar/plugins/aerospace.sh | 7 + sketchybar/plugins/battery.sh | 28 + sketchybar/plugins/clock.sh | 8 + sketchybar/plugins/front_app.sh | 10 + sketchybar/plugins/space.sh | 7 + sketchybar/plugins/volume.sh | 20 + sketchybar/plugins/wifi.sh | 12 + sketchybar/sketchybarrc | 128 + starship.toml | 68 + 54 files changed, 7522 insertions(+) create mode 100644 aerospace/.aerospace.toml.swp create mode 100644 aerospace/aerospace.toml create mode 100644 ghostty/.DS_Store create mode 100644 ghostty/config create mode 100644 ghostty/config-default create mode 100644 ghostty/ghostty-theme create mode 100644 ghostty/reload-config.scpt create mode 100644 ghostty/shaders/animated-gradient-shader.glsl create mode 100644 ghostty/shaders/bettercrt.glsl create mode 100644 ghostty/shaders/bloom.glsl create mode 100644 ghostty/shaders/bloom025.glsl create mode 100644 ghostty/shaders/bloom050.glsl create mode 100644 ghostty/shaders/bloom060.glsl create mode 100644 ghostty/shaders/bloom075.glsl create mode 100644 ghostty/shaders/bloom1.glsl create mode 100644 ghostty/shaders/crt.glsl create mode 100644 ghostty/shaders/cubes.glsl create mode 100644 ghostty/shaders/cursor_blaze.glsl create mode 100644 ghostty/shaders/cursor_blaze_no_trail.glsl create mode 100644 ghostty/shaders/cursor_smear.glsl create mode 100644 ghostty/shaders/cursor_smear_fade.glsl create mode 100644 ghostty/shaders/cursor_warp.glsl create mode 100644 ghostty/shaders/dither.glsl create mode 100644 ghostty/shaders/drunkard.glsl create mode 100644 ghostty/shaders/fireworks-rockets.glsl create mode 100644 ghostty/shaders/fireworks.glsl create mode 100644 ghostty/shaders/gears-and-belts.glsl create mode 100644 ghostty/shaders/glitchy.glsl create mode 100644 ghostty/shaders/glow-rgbsplit-twitchy.glsl create mode 100644 ghostty/shaders/gradient-background.glsl create mode 100644 ghostty/shaders/inside-the-matrix.glsl create mode 100644 ghostty/shaders/just-snow.glsl create mode 100644 ghostty/shaders/matrix-hallway.glsl create mode 100644 ghostty/shaders/negative.glsl create mode 100644 ghostty/shaders/retro-terminal.glsl create mode 100644 ghostty/shaders/ripple_cursor.glsl create mode 100644 ghostty/shaders/smoke-and-ghost.glsl create mode 100644 ghostty/shaders/sparks-from-fire.glsl create mode 100644 ghostty/shaders/spotlight.glsl create mode 100644 ghostty/shaders/starfield-colors.glsl create mode 100644 ghostty/shaders/starfield.glsl create mode 100644 ghostty/shaders/tft.glsl create mode 100644 ghostty/shaders/underwater.glsl create mode 100644 ghostty/shaders/water.glsl create mode 100644 sketchybar/.DS_Store create mode 100755 sketchybar/plugins/aerospace.sh create mode 100755 sketchybar/plugins/battery.sh create mode 100755 sketchybar/plugins/clock.sh create mode 100755 sketchybar/plugins/front_app.sh create mode 100755 sketchybar/plugins/space.sh create mode 100755 sketchybar/plugins/volume.sh create mode 100755 sketchybar/plugins/wifi.sh create mode 100755 sketchybar/sketchybarrc create mode 100644 starship.toml diff --git a/aerospace/.aerospace.toml.swp b/aerospace/.aerospace.toml.swp new file mode 100644 index 0000000000000000000000000000000000000000..eaa1ffe80b26da7243cab828610a0d3e4316c693 GIT binary patch literal 24576 zcmeI4Ym6kfNNPXLfeS_6}OaWM}Pc%y_LG50H%4OLg__ z?($UE?XAZ=*1JJM1f&opg2ai#he!$JA(SYJk=8*G`GS-;QWQcWBt-H7ArS%*Ur2&@ z{m!jN_w+pQj3E+HmGswi)xG!Bx&M3av(B0J?5|u}R_9u$9j=!<&Xc#V_doHCw>j@y zJ?0FyGf*>7Gf*>7Gf*>7Gf*>7Gf*?|!^c26 zJnsAk)p|)$wYB2!v5CKT6!)(${ys60e!RGURq^*j6Y2l?U-@-k@%&R0>BVjRr)HpL zpk|W=Q;3R@GMvbKMB5kkK^11Pl6}F8khyI0LQ_<-%Wn-Ztx6v7uW_qXoGvf zH-8Md;90N+ehPf+M;+%c!B@b?!S8_I25$m)famVw9=ruy0j~m|{SofLdGH@EbDS@L z&x6l_r@+g>pWlfN;GLikPJ*8X$H7a%pK;*v$KWmCKJZlzI5xmFa18w0OVJm627DC! zKG*_Jf~(*c!1p**`8;?l*Z>)L0-ObRgD=6k@cx1Fux0P|Rb11`RS&uAdOK;!t-ZRZ zo2on4RIOG^e#|=ZR5CuIw})OwMcJUOV+v4=``KpkgJSuUvTS~Lt}6d%Sx^LWQIaxc z?oqy9)@f>AkY`g~Q?;AQFEqO0$m40X7=~(Sk|bz{T3(zi(7FTD(XD|OM6GrZb%LmO z)tOcgd12W0{B^bAg_%|-gRa^(nKFYQRcYTAKDD5B6;V?8RpJP8@TF%iIUWdQiOBulK&u? z9xHp1?H}}`Y4tFAVBhJcM)OU&lG#k?IARL!YfdRI>Qt$P@=AAlnmkr{^0aa*wLL>@ zs&Rc26WVS#YxGrj;0=dG@1)@l*Dq8G!&sN_)n*_ckClj%;7c#KOT7b6-D5w@D> zZWgLy@adSSk*X}wxdEZYf}bU>-}j=P?!eE~z-+*r5%qK9a6|9Lw(H9n7*AD2bf@gGV};imW2Fn@ z886;=;X`(*+TQOGIfpSW-wXyAb}~KE?~oGm(Y(~Etg|cjCi9OBTT3y+GL6}d8G)IF zXie+5*xYFtVX$6UMqBs2jljf|UABaGO&CgVw2h+d&|-hmGG$lHTPks!Vi4n6xd1Xvy6QPsil^SKeS?Y09Dzz^Gp$GMLR7!(TCsO%c zLT$=TdZCFscG9hWGT3%xZ2@=lvlK1+U!qerOD9rA@0TH;i6_rn^lh>~&eO&&VGWfG zwI6gDJ#4uoxS{F5G7RJjl#-AjbKN1w%)G{!gpTaM6q$J7g~1JL1g;sfk_u8iZW%HI zx{*#;)r?F>M#nVH^xk3^F_>keJ+e=$N5@~t;_(P|*rBuIFs;R@>!ogJdVv_SRSb6I zxvJJ!%1f2a!B}?HQL2%wYi8f=wihecO<6$ou)fM~_*%6ZxK<8$4_&^nx^i*p+OJ-| z^2o|#ix)1QfA!+UE0^uhYr7H~@($N;H0AFMOS_r2m-M;STiSOS9I6)-0|c6{(WsA_ zH0W-tm63L=8!^%+z87e)U&bY zOB%8=inB=B)H0K8w^9%3rDa!>nMYRdM$x@S3Nb3BV^T&oP*jOUN&fa7f~A5oS?sRi z(JHvpFdHh;xy=~Oo~oX$kOh9mo8IV1?WEsk*AK+a$rY^mig)U9RH<`ipX zd4%SjfZTT41w=QGlUP>u@^5U!lY3zwbi+(kzn zb5^pS#(ACdljex;V)AWfbQE%CY9|?iX>ARIp%zB=SM*?+^Aj@pLNkm_YNCx{#K#x^ ze@!k8*ACK6j{}>i#TP%}_^86?CY44w-!=Wd4#R${*EdOOKf3H=7Y8%4vWM_wXwRuy z{=r5e`~Qd8|3438|6ls=e}ldK--1tq3_JDF-_3&e43GQZSeS`}HW>tm|6aaKq& z98O}+CMqwM!a0^hjd7pZF;CebNivz>wx}`i(8zo93HFu;su%4Tjj?emY&$kE?r@&BMUrDw4Trf+2S~i ze~R@-vc+}cTLH1=_{VzQ@NexV$`yXjeB$2-d_C^!d<3tWUCzga*a?s4G5_OM-UcIk zzK+JZ?UrTj_y3RJtNu-V+GYP=#`nv2|3|=g+24N7pJU9#f1%LmqfIk7xfe>5)4}zZs$HBMo{r@t!4SaAvxC{IZKK~yFzX@)E zH-ZIl4*VVd|DOUHOabBQec(FyG;F8s4Sow;0aM^R z`2GJg_&WGg@GN)_kgFcw%0agt-|Rf|!!o`-7G^yT#l3Vm%o$mVxKozsiIh+(nuSbblt+`Fzvs%*Y78Fa%z#8x`E$(nE1?}QT|fV&g1#SM~89( zw>7A$kuSOCD|UB(Oqd@@%`=}pAoJPD%x4bBd}cE9+yR;ACNrNtAoJ-w^C5kK$84C^ z-^Ij;GkJ5>M2Zhfic4s>pPoi3OQRIa@F-=BR7>Y5WsE_~-6&;@E=$xXWsDok$|&VU z5>W{n8Q!c^o^_cxU?&6dC4TKZzOf|(=XNE#W%5y5BY)XQgWL+s&@LMaE%Gdx zgm~rYYzQV2WyxP9+x7oMh9cT4FK?$qo8hRnkg$nS9V+efIE8$RQz;-jpvImld6n{{ z@jA%{s3YrCDLtxjJ#pe zecKEPv~nXgvp9;;NoF3-zu)CwHA@+`6N`*u_!~tCjN%}wc#M%z40RkB+kK02Ho##l zc4DH;QR`gnWo(u4_HN`FOe-zBCB90Q_qICXtnQ_{$SjXKL|plCFieYQQe-@ENliVj z;{o36;Z%`h2d|CY%qCtgP`S8Y7iCV`02`tPf-|RzN0n=NBm~n?HVh+=wvk{D_O}w6 zVU%qu%oKlWs|ODB?BUTuy_QOfmvurzq<&Ub;b_Z@2@A<>Xd>*j9M6y7r(V>05q63F z$fIak*+>9NOsEdQVNIzMakpt4HmMQ^7o`raT8v|2kVY}X(p8$Y-DcEO*|3?9R>dpS zu8XiW!eW+#C`-zi;bo#FgJHN`-m{!bit<(9u?>*%!ZPsqLa4pC%)dnJ3;`|6Uc6pC z3N{EVD(@~z%TzblGcS|?4LP3JeI*h`XQCAXP}RvxE0-nCu5I{UpC}WFjyfZZi+nf7}B^*xxbJ zxn-v~odDSSYj^}!0G4z|e0!LiKX;$mO=XNo=R4l%+M^U#H3n{7?yPATh;Z#DKY7=8a}K}wwh2ZPUrhul*4+Wq7;w ~/github/dotfiles-latest/ghostty/config-default + +# To get syntax highlighting in neovim, see +# ~/github/dotfiles-latest/neovim/neobean/lua/plugins/ghostty.lua + +# HACK: How to setup the Ghostty terminal, is it just hype? READ PINNED MESSAGE +# https://youtu.be/rCiq5CyFFhA + +# No way of reloading config via command yet, only via keymap cmd+shift+, +# Created a script to do it so that its reloaded with my colorscheme selector + +# Additional configuration files to read. This configuration can be repeated +# to read multiple configuration files. Configuration files themselves can +# load more configuration files. Paths are relative to the file containing the +# `config-file` directive. For command-line arguments, paths are relative to +# the current working directory. +# +# Prepend a ? character to the file path to suppress errors if the file does +# not exist. If you want to include a file that begins with a literal ? +# character, surround the file path in double quotes ("). +# + +# Cycles are not allowed. If a cycle is detected, an error will be logged and +# the configuration file will be ignored. +# config-file = ghostty-theme +theme = Catppuccin Mocha +cursor-color = #cba6f7 + +# Some shaders can be found in this repo, they're usually uploaded to discord +# https://github.com/hackrmomo/ghostty-shaders +# custom-shader = shaders/animated-gradient-shader.glsl +# custom-shader = shaders/bettercrt.glsl +# custom-shader = shaders/bloom.glsl +# custom-shader = shaders/bloom1.glsl +# custom-shader = shaders/bloom075.glsl +# custom-shader = shaders/bloom060.glsl +# custom-shader = shaders/bloom050.glsl +# custom-shader = shaders/bloom025.glsl +# custom-shader = shaders/bloom050.glsl +custom-shader = shaders/bloom060.glsl +# custom-shader = shaders/bloom075.glsl +# custom-shader = shaders/bloom1.glsl +# custom-shader = shaders/crt.glsl +# custom-shader = shaders/cubes.glsl +# custom-shader = shaders/dither.glsl +# custom-shader = shaders/drunkard.glsl +# custom-shader = shaders/fireworks-rockets.glsl +# custom-shader = shaders/fireworks.glsl +# custom-shader = shaders/gears-and-belts.glsl +# custom-shader = shaders/glitchy.glsl +# custom-shader = shaders/glow-rgbsplit-twitchy.glsl +# custom-shader = shaders/gradient-background.glsl +# custom-shader = shaders/inside-the-matrix.glsl +# custom-shader = shaders/just-snow.glsl +# custom-shader = shaders/matrix-hallway.glsl +# custom-shader = shaders/negative.glsl +# custom-shader = shaders/retro-terminal.glsl +# custom-shader = shaders/smoke-and-ghost.glsl +# custom-shader = shaders/sparks-from-fire.glsl +# custom-shader = shaders/spotlight.glsl +# custom-shader = shaders/starfield-colors.glsl +# custom-shader = shaders/starfield.glsl +# custom-shader = shaders/tft.glsl +# custom-shader = shaders/underwater.glsl +# custom-shader = shaders/water.glsl +# custom-shader = shaders/cursor_blaze.glsl +custom-shader = shaders/cursor_blaze_no_trail.glsl +# custom-shader = shaders/cursor_smear.glsl +# custom-shader = shaders/cursor_smear_fade.glsl +custom-shader = shaders/cursor_warp.glsl +custom-shader = shaders/ripple_cursor.glsl + +# The command to run, usually a shell. If this is not an absolute path, it'll +# be looked up in the `PATH`. If this is not set, a default will be looked up +# from your system. The rules for the default lookup are: +# +# * `SHELL` environment variable +# +# * `passwd` entry (user information) +# +# This can contain additional arguments to run the command with. If additional +# arguments are provided, the command will be executed using `/bin/sh -c`. +# Ghostty does not do any shell command parsing. +# +# If you're using the `ghostty` CLI there is also a shortcut to run a command +# with arguments directly: you can use the `-e` flag. For example: `ghostty -e +# fish --with --custom --args`. The `-e` flag automatically forces some +# other behaviors as well: +# +# * `gtk-single-instance=false` - This ensures that a new instance is +# launched and the CLI args are respected. +# +# * `quit-after-last-window-closed=true` - This ensures that the Ghostty +# process will exit when the command exits. Additionally, the +# `quit-after-last-window-closed-delay` is unset. +# ############################################################################ +# The following command checks if tmux is installed. +# If tmux is installed, it automatically attaches to an existing tmux session. +# If no tmux session exists, a new one is created. +# If tmux is not installed, it simply starts zsh without tmux. +# +# For this to work properly, you need to make sure that your shell is configured +# for homebrew, so you should have this line: +# eval "$(/opt/homebrew/bin/brew shellenv)" +# In your ~/.zprofile file +# If you don't have that line, or if the file doesn't exist, run this: +# echo '' >>~/.zprofile && echo '# Configure shell for brew' >>~/.zprofile && echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >>~/.zprofile && eval "$(/opt/homebrew/bin/brew shellenv)" +# +# This assumes you installed tmux through brew if using macos +# command = zsh --login -c "if command -v tmux >/dev/null 2>&1; then tmux attach || tmux; else zsh; fi" +# command = zsh --login -c "if command -v tmux >/dev/null 2>&1; then $HOME/github/dotfiles-latest/tmux/tools/prime/tmux-sessionizer.sh $HOME/github/dotfiles-latest || (tmux attach 2>/dev/null || tmux); else exec zsh; fi" + +# Horizontal window padding. This applies padding between the terminal cells +# and the left and right window borders. The value is in points, meaning that +# it will be scaled appropriately for screen DPI. +# +# If this value is set too large, the screen will render nothing, because the +# grid will be completely squished by the padding. It is up to you as the user +# to pick a reasonable value. If you pick an unreasonable value, a warning +# will appear in the logs. +# +# Changing this configuration at runtime will only affect new terminals, i.e. +# new windows, tabs, etc. +# +# To set a different left and right padding, specify two numerical values +# separated by a comma. For example, `window-padding-x = 2,4` will set the +# left padding to 2 and the right padding to 4. If you want to set both +# paddings to the same value, you can use a single value. For example, +# `window-padding-x = 2` will set both paddings to 2. +window-padding-x = 4,2 + +# Vertical window padding. This applies padding between the terminal cells and +# the top and bottom window borders. The value is in points, meaning that it +# will be scaled appropriately for screen DPI. +# +# If this value is set too large, the screen will render nothing, because the +# grid will be completely squished by the padding. It is up to you as the user +# to pick a reasonable value. If you pick an unreasonable value, a warning +# will appear in the logs. +# +# Changing this configuration at runtime will only affect new terminals, +# i.e. new windows, tabs, etc. +# +# To set a different top and bottom padding, specify two numerical values +# separated by a comma. For example, `window-padding-y = 2,4` will set the +# top padding to 2 and the bottom padding to 4. If you want to set both +# paddings to the same value, you can use a single value. For example, +# `window-padding-y = 2` will set both paddings to 2. +window-padding-y = 6,0 + +font-family = FiraCode Nerd Font +font-size = 15 + +# Valid values: +# +# * `true` +# * `false` - windows won't have native decorations, i.e. titlebar and +# borders. On macOS this also disables tabs and tab overview. +# +# The "toggle_window_decoration" keybind action can be used to create +# a keybinding to toggle this setting at runtime. +# +# Changing this configuration in your configuration and reloading will +# only affect new windows. Existing windows will not be affected. +# +# macOS: To hide the titlebar without removing the native window borders +# or rounded corners, use `macos-titlebar-style = hidden` instead. +macos-titlebar-style = hidden + +# Confirms that a surface should be closed before closing it. This defaults to +# true. If set to false, surfaces will close without any confirmation. +confirm-close-surface = false + +# Toggle the "quick" terminal. The quick terminal is a terminal that +# appears on demand from a keybinding, often sliding in from a screen +# edge such as the top. This is useful for quick access to a terminal +# without having to open a new window or tab. +# +# When the quick terminal loses focus, it disappears. The terminal state +# is preserved between appearances, so you can always press the keybinding +# to bring it back up. +# +# The quick terminal has some limitations: +# +# - It is a singleton; only one instance can exist at a time. +# - It does not support tabs. +# - It will not be restored when the application is restarted +# (for systems that support window restoration). +# - It supports fullscreen, but fullscreen will always be a non-native +# fullscreen (macos-non-native-fullscreen = true). This only applies +# to the quick terminal window. This is a requirement due to how +# the quick rerminal is rendered. +# +# See the various configurations for the quick terminal in the +# configuration file to customize its behavior. +# +# `global:` - Make the keybind global. By default, keybinds only work +# within Ghostty and under the right conditions (application focused, +# sometimes terminal focused, etc.). If you want a keybind to work +# globally across your system (i.e. even when Ghostty is not focused), +# specify this prefix. This prefix implies `all:`. Note: this does not +# work in all environments; see the additional notes below for more +# information. +# keybind = global:cmd+s=toggle_quick_terminal +# keybind = cmd+s=toggle_quick_terminal + +# If `true`, the *Option* key will be treated as *Alt*. This makes terminal +# sequences expecting *Alt* to work properly, but will break Unicode input +# sequences on macOS if you use them via the *Alt* key. You may set this to +# `false` to restore the macOS *Alt* key unicode sequences but this will break +# terminal sequences expecting *Alt* to work. +# +# The values `left` or `right` enable this for the left or right *Option* +# key, respectively. +# +# Note that if an *Option*-sequence doesn't produce a printable character, it +# will be treated as *Alt* regardless of this setting. (i.e. `alt+ctrl+a`). +# +# This does not work with GLFW builds. +macos-option-as-alt = right + +# Duration (in seconds) of the quick terminal enter and exit animation. +# Set it to 0 to disable animation completely. This can be changed at +# runtime. +# quick-terminal-animation-duration = 0.1 +quick-terminal-animation-duration = 0.08 +# quick-terminal-animation-duration = 0 + +keybind = super+i=inspector:toggle +keybind = super+r=reload_config + +# This doesn't work when in tmux, if outside tmux the regular ctrl+l works +# keybind = super+k=clear_screen + +# When not running tmux I see what C-enter sends +# I can do `/bin/cat -v` and then pressed C-enter +# Ghostty sends: ^[[27;5;13~ +# +# The problem is that when I run tmux, nothing is sent, so I'm sending those +# keys in my tmux.conf file + +# Customize the macOS app icon. +# +# This only affects the icon that appears in the dock, application +# switcher, etc. This does not affect the icon in Finder because +# that is controlled by a hardcoded value in the signed application +# bundle and can't be changed at runtime. For more details on what +# exactly is affected, see the `NSApplication.icon` Apple documentation; +# that is the API that is being used to set the icon. +# +# WARNING: The `custom-style` option is _experimental_. We may change +# the format of the custom styles in the future. We're still finalizing +# the exact layers and customization options that will be available. +# +# Other caveats: +# +# * The icon in the update dialog will always be the official icon. +# This is because the update dialog is managed through a +# separate framework and cannot be customized without significant +# effort. +# +# Valid values: +# +# * `official` - Use the official Ghostty icon. +# * `blueprint`, `chalkboard`, `microchip`, `glass`, `holographic`, +# `paper`, `retro`, `xray` - Official variants of the Ghostty icon +# hand-created by artists (no AI). +# * `custom-style` - Use the official Ghostty icon but with custom +# styles applied to various layers. The custom styles must be +# specified using the additional `macos-icon`-prefixed configurations. +# The `macos-icon-ghost-color` and `macos-icon-screen-color` +# configurations are required for this style. +# +macos-icon = glass + +# The opacity level (opposite of transparency) of the background. A value of +# 1 is fully opaque and a value of 0 is fully transparent. A value less than 0 +# or greater than 1 will be clamped to the nearest valid value. +# +# On macOS, background opacity is disabled when the terminal enters native +# fullscreen. This is because the background becomes gray and it can cause +# widgets to show through which isn't generally desirable. +# +# On macOS, changing this configuration requires restarting Ghostty completely. +background-opacity = 0.9 +background-blur = true +unfocused-split-opacity = 0.7 diff --git a/ghostty/config-default b/ghostty/config-default new file mode 100644 index 0000000..6468c7e --- /dev/null +++ b/ghostty/config-default @@ -0,0 +1,2522 @@ +# The font families to use. +# +# You can generate the list of valid values using the CLI: +# +# ghostty +list-fonts +# +# This configuration can be repeated multiple times to specify preferred +# fallback fonts when the requested codepoint is not available in the primary +# font. This is particularly useful for multiple languages, symbolic fonts, +# etc. +# +# Notes on emoji specifically: On macOS, Ghostty by default will always use +# Apple Color Emoji and on Linux will always use Noto Emoji. You can +# override this behavior by specifying a font family here that contains +# emoji glyphs. +# +# The specific styles (bold, italic, bold italic) do not need to be +# explicitly set. If a style is not set, then the regular style (font-family) +# will be searched for stylistic variants. If a stylistic variant is not +# found, Ghostty will use the regular style. This prevents falling back to a +# different font family just to get a style such as bold. This also applies +# if you explicitly specify a font family for a style. For example, if you +# set `font-family-bold = FooBar` and "FooBar" cannot be found, Ghostty will +# use whatever font is set for `font-family` for the bold style. +# +# Finally, some styles may be synthesized if they are not supported. +# For example, if a font does not have an italic style and no alternative +# italic font is specified, Ghostty will synthesize an italic style by +# applying a slant to the regular style. If you want to disable these +# synthesized styles then you can use the `font-style` configurations +# as documented below. +# +# You can disable styles completely by using the `font-style` set of +# configurations. See the documentation for `font-style` for more information. +# +# If you want to overwrite a previous set value rather than append a fallback, +# specify the value as `""` (empty string) to reset the list and then set the +# new values. For example: +# +# font-family = "" +# font-family = "My Favorite Font" +# +# Setting any of these as CLI arguments will automatically clear the +# values set in configuration files so you don't need to specify +# `--font-family=""` before setting a new value. You only need to specify +# this within config files if you want to clear previously set values in +# configuration files or on the CLI if you want to clear values set on the +# CLI. +# +# Changing this configuration at runtime will only affect new terminals, i.e. +# new windows, tabs, etc. +font-family = + +font-family-bold = +font-family-italic = +font-family-bold-italic = +# The named font style to use for each of the requested terminal font styles. +# This looks up the style based on the font style string advertised by the +# font itself. For example, "Iosevka Heavy" has a style of "Heavy". +# +# You can also use these fields to completely disable a font style. If you set +# the value of the configuration below to literal `false` then that font style +# will be disabled. If the running program in the terminal requests a disabled +# font style, the regular font style will be used instead. +# +# These are only valid if its corresponding font-family is also specified. If +# no font-family is specified, then the font-style is ignored unless you're +# disabling the font style. +font-style = default + +font-style-bold = default +font-style-italic = default +font-style-bold-italic = default +# Control whether Ghostty should synthesize a style if the requested style is +# not available in the specified font-family. +# +# Ghostty can synthesize bold, italic, and bold italic styles if the font +# does not have a specific style. For bold, this is done by drawing an +# outline around the glyph of varying thickness. For italic, this is done by +# applying a slant to the glyph. For bold italic, both of these are applied. +# +# Synthetic styles are not perfect and will generally not look as good +# as a font that has the style natively. However, they are useful to +# provide styled text when the font does not have the style. +# +# Set this to "false" or "true" to disable or enable synthetic styles +# completely. You can disable specific styles using "no-bold", "no-italic", +# and "no-bold-italic". You can disable multiple styles by separating them +# with a comma. For example, "no-bold,no-italic". +# +# Available style keys are: `bold`, `italic`, `bold-italic`. +# +# If synthetic styles are disabled, then the regular style will be used +# instead if the requested style is not available. If the font has the +# requested style, then the font will be used as-is since the style is +# not synthetic. +# +# Warning: An easy mistake is to disable `bold` or `italic` but not +# `bold-italic`. Disabling only `bold` or `italic` will NOT disable either +# in the `bold-italic` style. If you want to disable `bold-italic`, you must +# explicitly disable it. You cannot partially disable `bold-italic`. +# +# By default, synthetic styles are enabled. +font-synthetic-style = bold,italic,bold-italic + +# Apply a font feature. To enable multiple font features you can repeat +# this multiple times or use a comma-separated list of feature settings. +# +# The syntax for feature settings is as follows, where `feat` is a feature: +# +# * Enable features with e.g. `feat`, `+feat`, `feat on`, `feat=1`. +# * Disabled features with e.g. `-feat`, `feat off`, `feat=0`. +# * Set a feature value with e.g. `feat=2`, `feat = 3`, `feat 4`. +# * Feature names may be wrapped in quotes, meaning this config should be +# syntactically compatible with the `font-feature-settings` CSS property. +# +# The syntax is fairly loose, but invalid settings will be silently ignored. +# +# The font feature will apply to all fonts rendered by Ghostty. A future +# enhancement will allow targeting specific faces. +# +# To disable programming ligatures, use `-calt` since this is the typical +# feature name for programming ligatures. To look into what font features +# your font has and what they do, use a font inspection tool such as +# [fontdrop.info](https://fontdrop.info). +# +# To generally disable most ligatures, use `-calt, -liga, -dlig`. +font-feature = + +# Font size in points. This value can be a non-integer and the nearest integer +# pixel size will be selected. If you have a high dpi display where 1pt = 2px +# then you can get an odd numbered pixel size by specifying a half point. +# +# For example, 13.5pt @ 2px/pt = 27px +# +# Changing this configuration at runtime will only affect new terminals, +# i.e. new windows, tabs, etc. Note that you may still not see the change +# depending on your `window-inherit-font-size` setting. If that setting is +# true, only the first window will be affected by this change since all +# subsequent windows will inherit the font size of the previous window. +# +# On Linux with GTK, font size is scaled according to both display-wide and +# text-specific scaling factors, which are often managed by your desktop +# environment (e.g. the GNOME display scale and large text settings). +font-size = 13 + +# A repeatable configuration to set one or more font variations values for +# a variable font. A variable font is a single font, usually with a filename +# ending in `-VF.ttf` or `-VF.otf` that contains one or more configurable axes +# for things such as weight, slant, etc. Not all fonts support variations; +# only fonts that explicitly state they are variable fonts will work. +# +# The format of this is `id=value` where `id` is the axis identifier. An axis +# identifier is always a 4 character string, such as `wght`. To get the list +# of supported axes, look at your font documentation or use a font inspection +# tool. +# +# Invalid ids and values are usually ignored. For example, if a font only +# supports weights from 100 to 700, setting `wght=800` will do nothing (it +# will not be clamped to 700). You must consult your font's documentation to +# see what values are supported. +# +# Common axes are: `wght` (weight), `slnt` (slant), `ital` (italic), `opsz` +# (optical size), `wdth` (width), `GRAD` (gradient), etc. +font-variation = + +font-variation-bold = +font-variation-italic = +font-variation-bold-italic = +# Force one or a range of Unicode codepoints to map to a specific named font. +# This is useful if you want to support special symbols or if you want to use +# specific glyphs that render better for your specific font. +# +# The syntax is `codepoint=fontname` where `codepoint` is either a single +# codepoint or a range. Codepoints must be specified as full Unicode +# hex values, such as `U+ABCD`. Codepoints ranges are specified as +# `U+ABCD-U+DEFG`. You can specify multiple ranges for the same font separated +# by commas, such as `U+ABCD-U+DEFG,U+1234-U+5678=fontname`. The font name is +# the same value as you would use for `font-family`. +# +# This configuration can be repeated multiple times to specify multiple +# codepoint mappings. +# +# Changing this configuration at runtime will only affect new terminals, +# i.e. new windows, tabs, etc. +font-codepoint-map = + +# Draw fonts with a thicker stroke, if supported. +# This is currently only supported on macOS. +font-thicken = false + +# Strength of thickening when `font-thicken` is enabled. +# +# Valid values are integers between `0` and `255`. `0` does not correspond to +# *no* thickening, rather it corresponds to the lightest available thickening. +# +# Has no effect when `font-thicken` is set to `false`. +# +# This is currently only supported on macOS. +font-thicken-strength = 255 + +# What color space to use when performing alpha blending. +# +# This affects the appearance of text and of any images with transparency. +# Additionally, custom shaders will receive colors in the configured space. +# +# Valid values: +# +# * `native` - Perform alpha blending in the native color space for the OS. +# On macOS this corresponds to Display P3, and on Linux it's sRGB. +# +# * `linear` - Perform alpha blending in linear space. This will eliminate +# the darkening artifacts around the edges of text that are very visible +# when certain color combinations are used (e.g. red / green), but makes +# dark text look much thinner than normal and light text much thicker. +# This is also sometimes known as "gamma correction". +# (Currently only supported on macOS. Has no effect on Linux.) +# +# * `linear-corrected` - Same as `linear`, but with a correction step applied +# for text that makes it look nearly or completely identical to `native`, +# but without any of the darkening artifacts. +alpha-blending = native + +# All of the configurations behavior adjust various metrics determined by the +# font. The values can be integers (1, -1, etc.) or a percentage (20%, -15%, +# etc.). In each case, the values represent the amount to change the original +# value. +# +# For example, a value of `1` increases the value by 1; it does not set it to +# literally 1. A value of `20%` increases the value by 20%. And so on. +# +# There is little to no validation on these values so the wrong values (e.g. +# `-100%`) can cause the terminal to be unusable. Use with caution and reason. +# +# Some values are clamped to minimum or maximum values. This can make it +# appear that certain values are ignored. For example, many `*-thickness` +# adjustments cannot go below 1px. +# +# `adjust-cell-height` has some additional behaviors to describe: +# +# * The font will be centered vertically in the cell. +# +# * The cursor will remain the same size as the font, but may be +# adjusted separately with `adjust-cursor-height`. +# +# * Powerline glyphs will be adjusted along with the cell height so +# that things like status lines continue to look aligned. +adjust-cell-width = + +adjust-cell-height = +# Distance in pixels or percentage adjustment from the bottom of the cell to the text baseline. +# Increase to move baseline UP, decrease to move baseline DOWN. +# See the notes about adjustments in `adjust-cell-width`. +adjust-font-baseline = + +# Distance in pixels or percentage adjustment from the top of the cell to the top of the underline. +# Increase to move underline DOWN, decrease to move underline UP. +# See the notes about adjustments in `adjust-cell-width`. +adjust-underline-position = + +# Thickness in pixels of the underline. +# See the notes about adjustments in `adjust-cell-width`. +adjust-underline-thickness = + +# Distance in pixels or percentage adjustment from the top of the cell to the top of the strikethrough. +# Increase to move strikethrough DOWN, decrease to move strikethrough UP. +# See the notes about adjustments in `adjust-cell-width`. +adjust-strikethrough-position = + +# Thickness in pixels or percentage adjustment of the strikethrough. +# See the notes about adjustments in `adjust-cell-width`. +adjust-strikethrough-thickness = + +# Distance in pixels or percentage adjustment from the top of the cell to the top of the overline. +# Increase to move overline DOWN, decrease to move overline UP. +# See the notes about adjustments in `adjust-cell-width`. +adjust-overline-position = + +# Thickness in pixels or percentage adjustment of the overline. +# See the notes about adjustments in `adjust-cell-width`. +adjust-overline-thickness = + +# Thickness in pixels or percentage adjustment of the bar cursor and outlined rect cursor. +# See the notes about adjustments in `adjust-cell-width`. +adjust-cursor-thickness = + +# Height in pixels or percentage adjustment of the cursor. Currently applies to all cursor types: +# bar, rect, and outlined rect. +# See the notes about adjustments in `adjust-cell-width`. +adjust-cursor-height = + +# Thickness in pixels or percentage adjustment of box drawing characters. +# See the notes about adjustments in `adjust-cell-width`. +adjust-box-thickness = + +# The method to use for calculating the cell width of a grapheme cluster. +# The default value is `unicode` which uses the Unicode standard to determine +# grapheme width. This results in correct grapheme width but may result in +# cursor-desync issues with some programs (such as shells) that may use a +# legacy method such as `wcswidth`. +# +# Valid values are: +# +# * `legacy` - Use a legacy method to determine grapheme width, such as +# wcswidth This maximizes compatibility with legacy programs but may result +# in incorrect grapheme width for certain graphemes such as skin-tone +# emoji, non-English characters, etc. +# +# This is called "legacy" and not something more specific because the +# behavior is undefined and we want to retain the ability to modify it. +# For example, we may or may not use libc `wcswidth` now or in the future. +# +# * `unicode` - Use the Unicode standard to determine grapheme width. +# +# If a running program explicitly enables terminal mode 2027, then `unicode` +# width will be forced regardless of this configuration. When mode 2027 is +# reset, this configuration will be used again. +# +# This configuration can be changed at runtime but will not affect existing +# terminals. Only new terminals will use the new configuration. +grapheme-width-method = unicode + +# FreeType load flags to enable. The format of this is a list of flags to +# enable separated by commas. If you prefix a flag with `no-` then it is +# disabled. If you omit a flag, its default value is used, so you must +# explicitly disable flags you don't want. You can also use `true` or `false` +# to turn all flags on or off. +# +# This configuration only applies to Ghostty builds that use FreeType. +# This is usually the case only for Linux builds. macOS uses CoreText +# and does not have an equivalent configuration. +# +# Available flags: +# +# * `hinting` - Enable or disable hinting, enabled by default. +# * `force-autohint` - Use the freetype auto-hinter rather than the +# font's native hinter. Enabled by default. +# * `monochrome` - Instructs renderer to use 1-bit monochrome +# rendering. This option doesn't impact the hinter. +# Enabled by default. +# * `autohint` - Use the freetype auto-hinter. Enabled by default. +# +# Example: `hinting`, `no-hinting`, `force-autohint`, `no-force-autohint` +freetype-load-flags = hinting,force-autohint,monochrome,autohint + +# A theme to use. This can be a built-in theme name, a custom theme +# name, or an absolute path to a custom theme file. Ghostty also supports +# specifying a different theme to use for light and dark mode. Each +# option is documented below. +# +# If the theme is an absolute pathname, Ghostty will attempt to load that +# file as a theme. If that file does not exist or is inaccessible, an error +# will be logged and no other directories will be searched. +# +# If the theme is not an absolute pathname, two different directories will be +# searched for a file name that matches the theme. This is case sensitive on +# systems with case-sensitive filesystems. It is an error for a theme name to +# include path separators unless it is an absolute pathname. +# +# The first directory is the `themes` subdirectory of your Ghostty +# configuration directory. This is `$XDG_CONFIG_DIR/ghostty/themes` or +# `~/.config/ghostty/themes`. +# +# The second directory is the `themes` subdirectory of the Ghostty resources +# directory. Ghostty ships with a multitude of themes that will be installed +# into this directory. On macOS, this list is in the +# `Ghostty.app/Contents/Resources/ghostty/themes` directory. On Linux, this +# list is in the `share/ghostty/themes` directory (wherever you installed the +# Ghostty "share" directory. +# +# To see a list of available themes, run `ghostty +list-themes`. +# +# A theme file is simply another Ghostty configuration file. They share +# the same syntax and same configuration options. A theme can set any valid +# configuration option so please do not use a theme file from an untrusted +# source. The built-in themes are audited to only set safe configuration +# options. +# +# Some options cannot be set within theme files. The reason these are not +# supported should be self-evident. A theme file cannot set `theme` or +# `config-file`. At the time of writing this, Ghostty will not show any +# warnings or errors if you set these options in a theme file but they will +# be silently ignored. +# +# Any additional colors specified via background, foreground, palette, etc. +# will override the colors specified in the theme. +# +# To specify a different theme for light and dark mode, use the following +# syntax: `light:theme-name,dark:theme-name`. For example: +# `light:rose-pine-dawn,dark:rose-pine`. Whitespace around all values are +# trimmed and order of light and dark does not matter. Both light and dark +# must be specified in this form. In this form, the theme used will be +# based on the current desktop environment theme. +# +# There are some known bugs with light/dark mode theming. These will +# be fixed in a future update: +# +# - macOS: titlebar tabs style is not updated when switching themes. +# +theme = + +# Background color for the window. +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +background = #282c34 + +# Foreground color for the window. +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +foreground = #ffffff + +# The foreground and background color for selection. If this is not set, then +# the selection color is just the inverted window background and foreground +# (note: not to be confused with the cell bg/fg). +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +selection-foreground = + +selection-background = +# Swap the foreground and background colors of cells for selection. This +# option overrides the `selection-foreground` and `selection-background` +# options. +# +# If you select across cells with differing foregrounds and backgrounds, the +# selection color will vary across the selection. +selection-invert-fg-bg = false + +# The minimum contrast ratio between the foreground and background colors. +# The contrast ratio is a value between 1 and 21. A value of 1 allows for no +# contrast (e.g. black on black). This value is the contrast ratio as defined +# by the [WCAG 2.0 specification](https://www.w3.org/TR/WCAG20/). +# +# If you want to avoid invisible text (same color as background), a value of +# 1.1 is a good value. If you want to avoid text that is difficult to read, a +# value of 3 or higher is a good value. The higher the value, the more likely +# that text will become black or white. +# +# This value does not apply to Emoji or images. +minimum-contrast = 1 + +# Color palette for the 256 color form that many terminal applications use. +# The syntax of this configuration is `N=COLOR` where `N` is 0 to 255 (for +# the 256 colors in the terminal color table) and `COLOR` is a typical RGB +# color code such as `#AABBCC` or `AABBCC`, or a named X11 color. +# +# The palette index can be in decimal, binary, octal, or hexadecimal. +# Decimal is assumed unless a prefix is used: `0b` for binary, `0o` for octal, +# and `0x` for hexadecimal. +# +# For definitions on the color indices and what they canonically map to, +# [see this cheat sheet](https://www.ditig.com/256-colors-cheat-sheet). +palette = 0=#1d1f21 +palette = 1=#cc6666 +palette = 2=#b5bd68 +palette = 3=#f0c674 +palette = 4=#81a2be +palette = 5=#b294bb +palette = 6=#8abeb7 +palette = 7=#c5c8c6 +palette = 8=#666666 +palette = 9=#d54e53 +palette = 10=#b9ca4a +palette = 11=#e7c547 +palette = 12=#7aa6da +palette = 13=#c397d8 +palette = 14=#70c0b1 +palette = 15=#eaeaea +palette = 16=#000000 +palette = 17=#00005f +palette = 18=#000087 +palette = 19=#0000af +palette = 20=#0000d7 +palette = 21=#0000ff +palette = 22=#005f00 +palette = 23=#005f5f +palette = 24=#005f87 +palette = 25=#005faf +palette = 26=#005fd7 +palette = 27=#005fff +palette = 28=#008700 +palette = 29=#00875f +palette = 30=#008787 +palette = 31=#0087af +palette = 32=#0087d7 +palette = 33=#0087ff +palette = 34=#00af00 +palette = 35=#00af5f +palette = 36=#00af87 +palette = 37=#00afaf +palette = 38=#00afd7 +palette = 39=#00afff +palette = 40=#00d700 +palette = 41=#00d75f +palette = 42=#00d787 +palette = 43=#00d7af +palette = 44=#00d7d7 +palette = 45=#00d7ff +palette = 46=#00ff00 +palette = 47=#00ff5f +palette = 48=#00ff87 +palette = 49=#00ffaf +palette = 50=#00ffd7 +palette = 51=#00ffff +palette = 52=#5f0000 +palette = 53=#5f005f +palette = 54=#5f0087 +palette = 55=#5f00af +palette = 56=#5f00d7 +palette = 57=#5f00ff +palette = 58=#5f5f00 +palette = 59=#5f5f5f +palette = 60=#5f5f87 +palette = 61=#5f5faf +palette = 62=#5f5fd7 +palette = 63=#5f5fff +palette = 64=#5f8700 +palette = 65=#5f875f +palette = 66=#5f8787 +palette = 67=#5f87af +palette = 68=#5f87d7 +palette = 69=#5f87ff +palette = 70=#5faf00 +palette = 71=#5faf5f +palette = 72=#5faf87 +palette = 73=#5fafaf +palette = 74=#5fafd7 +palette = 75=#5fafff +palette = 76=#5fd700 +palette = 77=#5fd75f +palette = 78=#5fd787 +palette = 79=#5fd7af +palette = 80=#5fd7d7 +palette = 81=#5fd7ff +palette = 82=#5fff00 +palette = 83=#5fff5f +palette = 84=#5fff87 +palette = 85=#5fffaf +palette = 86=#5fffd7 +palette = 87=#5fffff +palette = 88=#870000 +palette = 89=#87005f +palette = 90=#870087 +palette = 91=#8700af +palette = 92=#8700d7 +palette = 93=#8700ff +palette = 94=#875f00 +palette = 95=#875f5f +palette = 96=#875f87 +palette = 97=#875faf +palette = 98=#875fd7 +palette = 99=#875fff +palette = 100=#878700 +palette = 101=#87875f +palette = 102=#878787 +palette = 103=#8787af +palette = 104=#8787d7 +palette = 105=#8787ff +palette = 106=#87af00 +palette = 107=#87af5f +palette = 108=#87af87 +palette = 109=#87afaf +palette = 110=#87afd7 +palette = 111=#87afff +palette = 112=#87d700 +palette = 113=#87d75f +palette = 114=#87d787 +palette = 115=#87d7af +palette = 116=#87d7d7 +palette = 117=#87d7ff +palette = 118=#87ff00 +palette = 119=#87ff5f +palette = 120=#87ff87 +palette = 121=#87ffaf +palette = 122=#87ffd7 +palette = 123=#87ffff +palette = 124=#af0000 +palette = 125=#af005f +palette = 126=#af0087 +palette = 127=#af00af +palette = 128=#af00d7 +palette = 129=#af00ff +palette = 130=#af5f00 +palette = 131=#af5f5f +palette = 132=#af5f87 +palette = 133=#af5faf +palette = 134=#af5fd7 +palette = 135=#af5fff +palette = 136=#af8700 +palette = 137=#af875f +palette = 138=#af8787 +palette = 139=#af87af +palette = 140=#af87d7 +palette = 141=#af87ff +palette = 142=#afaf00 +palette = 143=#afaf5f +palette = 144=#afaf87 +palette = 145=#afafaf +palette = 146=#afafd7 +palette = 147=#afafff +palette = 148=#afd700 +palette = 149=#afd75f +palette = 150=#afd787 +palette = 151=#afd7af +palette = 152=#afd7d7 +palette = 153=#afd7ff +palette = 154=#afff00 +palette = 155=#afff5f +palette = 156=#afff87 +palette = 157=#afffaf +palette = 158=#afffd7 +palette = 159=#afffff +palette = 160=#d70000 +palette = 161=#d7005f +palette = 162=#d70087 +palette = 163=#d700af +palette = 164=#d700d7 +palette = 165=#d700ff +palette = 166=#d75f00 +palette = 167=#d75f5f +palette = 168=#d75f87 +palette = 169=#d75faf +palette = 170=#d75fd7 +palette = 171=#d75fff +palette = 172=#d78700 +palette = 173=#d7875f +palette = 174=#d78787 +palette = 175=#d787af +palette = 176=#d787d7 +palette = 177=#d787ff +palette = 178=#d7af00 +palette = 179=#d7af5f +palette = 180=#d7af87 +palette = 181=#d7afaf +palette = 182=#d7afd7 +palette = 183=#d7afff +palette = 184=#d7d700 +palette = 185=#d7d75f +palette = 186=#d7d787 +palette = 187=#d7d7af +palette = 188=#d7d7d7 +palette = 189=#d7d7ff +palette = 190=#d7ff00 +palette = 191=#d7ff5f +palette = 192=#d7ff87 +palette = 193=#d7ffaf +palette = 194=#d7ffd7 +palette = 195=#d7ffff +palette = 196=#ff0000 +palette = 197=#ff005f +palette = 198=#ff0087 +palette = 199=#ff00af +palette = 200=#ff00d7 +palette = 201=#ff00ff +palette = 202=#ff5f00 +palette = 203=#ff5f5f +palette = 204=#ff5f87 +palette = 205=#ff5faf +palette = 206=#ff5fd7 +palette = 207=#ff5fff +palette = 208=#ff8700 +palette = 209=#ff875f +palette = 210=#ff8787 +palette = 211=#ff87af +palette = 212=#ff87d7 +palette = 213=#ff87ff +palette = 214=#ffaf00 +palette = 215=#ffaf5f +palette = 216=#ffaf87 +palette = 217=#ffafaf +palette = 218=#ffafd7 +palette = 219=#ffafff +palette = 220=#ffd700 +palette = 221=#ffd75f +palette = 222=#ffd787 +palette = 223=#ffd7af +palette = 224=#ffd7d7 +palette = 225=#ffd7ff +palette = 226=#ffff00 +palette = 227=#ffff5f +palette = 228=#ffff87 +palette = 229=#ffffaf +palette = 230=#ffffd7 +palette = 231=#ffffff +palette = 232=#080808 +palette = 233=#121212 +palette = 234=#1c1c1c +palette = 235=#262626 +palette = 236=#303030 +palette = 237=#3a3a3a +palette = 238=#444444 +palette = 239=#4e4e4e +palette = 240=#585858 +palette = 241=#626262 +palette = 242=#6c6c6c +palette = 243=#767676 +palette = 244=#808080 +palette = 245=#8a8a8a +palette = 246=#949494 +palette = 247=#9e9e9e +palette = 248=#a8a8a8 +palette = 249=#b2b2b2 +palette = 250=#bcbcbc +palette = 251=#c6c6c6 +palette = 252=#d0d0d0 +palette = 253=#dadada +palette = 254=#e4e4e4 +palette = 255=#eeeeee + +# The color of the cursor. If this is not set, a default will be chosen. +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +cursor-color = + +# Swap the foreground and background colors of the cell under the cursor. This +# option overrides the `cursor-color` and `cursor-text` options. +cursor-invert-fg-bg = false + +# The opacity level (opposite of transparency) of the cursor. A value of 1 +# is fully opaque and a value of 0 is fully transparent. A value less than 0 +# or greater than 1 will be clamped to the nearest valid value. Note that a +# sufficiently small value such as 0.3 may be effectively invisible and may +# make it difficult to find the cursor. +cursor-opacity = 1 + +# The style of the cursor. This sets the default style. A running program can +# still request an explicit cursor style using escape sequences (such as `CSI +# q`). Shell configurations will often request specific cursor styles. +# +# Note that shell integration will automatically set the cursor to a bar at +# a prompt, regardless of this configuration. You can disable that behavior +# by specifying `shell-integration-features = no-cursor` or disabling shell +# integration entirely. +# +# Valid values are: +# +# * `block` +# * `bar` +# * `underline` +# * `block_hollow` +# +cursor-style = block + +# Sets the default blinking state of the cursor. This is just the default +# state; running programs may override the cursor style using `DECSCUSR` (`CSI +# q`). +# +# If this is not set, the cursor blinks by default. Note that this is not the +# same as a "true" value, as noted below. +# +# If this is not set at all (`null`), then Ghostty will respect DEC Mode 12 +# (AT&T cursor blink) as an alternate approach to turning blinking on/off. If +# this is set to any value other than null, DEC mode 12 will be ignored but +# `DECSCUSR` will still be respected. +# +# Valid values are: +# +# * ` ` (blank) +# * `true` +# * `false` +# +cursor-style-blink = + +# The color of the text under the cursor. If this is not set, a default will +# be chosen. +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +cursor-text = + +# Enables the ability to move the cursor at prompts by using `alt+click` on +# Linux and `option+click` on macOS. +# +# This feature requires shell integration (specifically prompt marking +# via `OSC 133`) and only works in primary screen mode. Alternate screen +# applications like vim usually have their own version of this feature but +# this configuration doesn't control that. +# +# It should be noted that this feature works by translating your desired +# position into a series of synthetic arrow key movements, so some weird +# behavior around edge cases are to be expected. This is unfortunately how +# this feature is implemented across terminals because there isn't any other +# way to implement it. +cursor-click-to-move = true + +# Hide the mouse immediately when typing. The mouse becomes visible again +# when the mouse is used (button, movement, etc.). Platform-specific behavior +# may dictate other scenarios where the mouse is shown. For example on macOS, +# the mouse is shown again when a new window, tab, or split is created. +mouse-hide-while-typing = false + +# Determines whether running programs can detect the shift key pressed with a +# mouse click. Typically, the shift key is used to extend mouse selection. +# +# The default value of `false` means that the shift key is not sent with +# the mouse protocol and will extend the selection. This value can be +# conditionally overridden by the running program with the `XTSHIFTESCAPE` +# sequence. +# +# The value `true` means that the shift key is sent with the mouse protocol +# but the running program can override this behavior with `XTSHIFTESCAPE`. +# +# The value `never` is the same as `false` but the running program cannot +# override this behavior with `XTSHIFTESCAPE`. The value `always` is the +# same as `true` but the running program cannot override this behavior with +# `XTSHIFTESCAPE`. +# +# If you always want shift to extend mouse selection even if the program +# requests otherwise, set this to `never`. +# +# Valid values are: +# +# * `true` +# * `false` +# * `always` +# * `never` +# +mouse-shift-capture = false + +# Multiplier for scrolling distance with the mouse wheel. Any value less +# than 0.01 or greater than 10,000 will be clamped to the nearest valid +# value. +# +# A value of "1" (default) scrolls the default amount. A value of "2" scrolls +# double the default amount. A value of "0.5" scrolls half the default amount. +# Et cetera. +mouse-scroll-multiplier = 1 + +# The opacity level (opposite of transparency) of the background. A value of +# 1 is fully opaque and a value of 0 is fully transparent. A value less than 0 +# or greater than 1 will be clamped to the nearest valid value. +# +# On macOS, background opacity is disabled when the terminal enters native +# fullscreen. This is because the background becomes gray and it can cause +# widgets to show through which isn't generally desirable. +# +# On macOS, changing this configuration requires restarting Ghostty completely. +background-opacity = 1 + +# Whether to blur the background when `background-opacity` is less than 1. +# +# Valid values are: +# +# * a nonnegative integer specifying the *blur intensity* +# * `false`, equivalent to a blur intensity of 0 +# * `true`, equivalent to the default blur intensity of 20, which is +# reasonable for a good looking blur. Higher blur intensities may +# cause strange rendering and performance issues. +# +# Supported on macOS and on some Linux desktop environments, including: +# +# * KDE Plasma (Wayland and X11) +# +# Warning: the exact blur intensity is _ignored_ under KDE Plasma, and setting +# this setting to either `true` or any positive blur intensity value would +# achieve the same effect. The reason is that KWin, the window compositor +# powering Plasma, only has one global blur setting and does not allow +# applications to specify individual blur settings. +# +# To configure KWin's global blur setting, open System Settings and go to +# "Apps & Windows" > "Window Management" > "Desktop Effects" and select the +# "Blur" plugin. If disabled, enable it by ticking the checkbox to the left. +# Then click on the "Configure" button and there will be two sliders that +# allow you to set background blur and noise intensities for all apps, +# including Ghostty. +# +# All other Linux desktop environments are as of now unsupported. Users may +# need to set environment-specific settings and/or install third-party plugins +# in order to support background blur, as there isn't a unified interface for +# doing so. +background-blur = false + +# The opacity level (opposite of transparency) of an unfocused split. +# Unfocused splits by default are slightly faded out to make it easier to see +# which split is focused. To disable this feature, set this value to 1. +# +# A value of 1 is fully opaque and a value of 0 is fully transparent. Because +# "0" is not useful (it makes the window look very weird), the minimum value +# is 0.15. This value still looks weird but you can at least see what's going +# on. A value outside of the range 0.15 to 1 will be clamped to the nearest +# valid value. +unfocused-split-opacity = 0.7 + +# The color to dim the unfocused split. Unfocused splits are dimmed by +# rendering a semi-transparent rectangle over the split. This sets the color of +# that rectangle and can be used to carefully control the dimming effect. +# +# This will default to the background color. +# +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +unfocused-split-fill = + +# The color of the split divider. If this is not set, a default will be chosen. +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +split-divider-color = + +# The command to run, usually a shell. If this is not an absolute path, it'll +# be looked up in the `PATH`. If this is not set, a default will be looked up +# from your system. The rules for the default lookup are: +# +# * `SHELL` environment variable +# +# * `passwd` entry (user information) +# +# This can contain additional arguments to run the command with. If additional +# arguments are provided, the command will be executed using `/bin/sh -c`. +# Ghostty does not do any shell command parsing. +# +# This command will be used for all new terminal surfaces, i.e. new windows, +# tabs, etc. If you want to run a command only for the first terminal surface +# created when Ghostty starts, use the `initial-command` configuration. +# +# Ghostty supports the common `-e` flag for executing a command with +# arguments. For example, `ghostty -e fish --with --custom --args`. +# This flag sets the `initial-command` configuration, see that for more +# information. +command = + +# This is the same as "command", but only applies to the first terminal +# surface created when Ghostty starts. Subsequent terminal surfaces will use +# the `command` configuration. +# +# After the first terminal surface is created (or closed), there is no +# way to run this initial command again automatically. As such, setting +# this at runtime works but will only affect the next terminal surface +# if it is the first one ever created. +# +# If you're using the `ghostty` CLI there is also a shortcut to set this +# with arguments directly: you can use the `-e` flag. For example: `ghostty -e +# fish --with --custom --args`. The `-e` flag automatically forces some +# other behaviors as well: +# +# * `gtk-single-instance=false` - This ensures that a new instance is +# launched and the CLI args are respected. +# +# * `quit-after-last-window-closed=true` - This ensures that the Ghostty +# process will exit when the command exits. Additionally, the +# `quit-after-last-window-closed-delay` is unset. +# +# * `shell-integration=detect` (if not `none`) - This prevents forcibly +# injecting any configured shell integration into the command's +# environment. With `-e` its highly unlikely that you're executing a +# shell and forced shell integration is likely to cause problems +# (e.g. by wrapping your command in a shell, setting env vars, etc.). +# This is a safety measure to prevent unexpected behavior. If you want +# shell integration with a `-e`-executed command, you must either +# name your binary appropriately or source the shell integration script +# manually. +# +initial-command = + +# If true, keep the terminal open after the command exits. Normally, the +# terminal window closes when the running command (such as a shell) exits. +# With this true, the terminal window will stay open until any keypress is +# received. +# +# This is primarily useful for scripts or debugging. +wait-after-command = false + +# The number of milliseconds of runtime below which we consider a process exit +# to be abnormal. This is used to show an error message when the process exits +# too quickly. +# +# On Linux, this must be paired with a non-zero exit code. On macOS, we allow +# any exit code because of the way shell processes are launched via the login +# command. +abnormal-command-exit-runtime = 250 + +# The size of the scrollback buffer in bytes. This also includes the active +# screen. No matter what this is set to, enough memory will always be +# allocated for the visible screen and anything leftover is the limit for +# the scrollback. +# +# When this limit is reached, the oldest lines are removed from the +# scrollback. +# +# Scrollback currently exists completely in memory. This means that the +# larger this value, the larger potential memory usage. Scrollback is +# allocated lazily up to this limit, so if you set this to a very large +# value, it will not immediately consume a lot of memory. +# +# This size is per terminal surface, not for the entire application. +# +# It is not currently possible to set an unlimited scrollback buffer. +# This is a future planned feature. +# +# This can be changed at runtime but will only affect new terminal surfaces. +scrollback-limit = 10000000 + +# Match a regular expression against the terminal text and associate clicking +# it with an action. This can be used to match URLs, file paths, etc. Actions +# can be opening using the system opener (e.g. `open` or `xdg-open`) or +# executing any arbitrary binding action. +# +# Links that are configured earlier take precedence over links that are +# configured later. +# +# A default link that matches a URL and opens it in the system opener always +# exists. This can be disabled using `link-url`. +# +# TODO: This can't currently be set! + +# Enable URL matching. URLs are matched on hover with control (Linux) or +# super (macOS) pressed and open using the default system application for +# the linked URL. +# +# The URL matcher is always lowest priority of any configured links (see +# `link`). If you want to customize URL matching, use `link` and disable this. +link-url = true + +# Whether to start the window in a maximized state. This setting applies +# to new windows and does not apply to tabs, splits, etc. However, this setting +# will apply to all new windows, not just the first one. +maximize = false + +# Start new windows in fullscreen. This setting applies to new windows and +# does not apply to tabs, splits, etc. However, this setting will apply to all +# new windows, not just the first one. +# +# On macOS, this setting does not work if window-decoration is set to +# "false", because native fullscreen on macOS requires window decorations +# to be set. +fullscreen = false + +# The title Ghostty will use for the window. This will force the title of the +# window to be this title at all times and Ghostty will ignore any set title +# escape sequences programs (such as Neovim) may send. +# +# If you want a blank title, set this to one or more spaces by quoting +# the value. For example, `title = " "`. This effectively hides the title. +# This is necessary because setting a blank value resets the title to the +# default value of the running program. +# +# This configuration can be reloaded at runtime. If it is set, the title +# will update for all windows. If it is unset, the next title change escape +# sequence will be honored but previous changes will not retroactively +# be set. This latter case may require you to restart programs such as Neovim +# to get the new title. +title = + +# The setting that will change the application class value. +# +# This controls the class field of the `WM_CLASS` X11 property (when running +# under X11), and the Wayland application ID (when running under Wayland). +# +# Note that changing this value between invocations will create new, separate +# instances, of Ghostty when running with `gtk-single-instance=true`. See that +# option for more details. +# +# The class name must follow the requirements defined [in the GTK +# documentation](https://docs.gtk.org/gio/type_func.Application.id_is_valid.html). +# +# The default is `com.mitchellh.ghostty`. +# +# This only affects GTK builds. +class = + +# This controls the instance name field of the `WM_CLASS` X11 property when +# running under X11. It has no effect otherwise. +# +# The default is `ghostty`. +# +# This only affects GTK builds. +x11-instance-name = + +# The directory to change to after starting the command. +# +# This setting is secondary to the `window-inherit-working-directory` +# setting. If a previous Ghostty terminal exists in the same process, +# `window-inherit-working-directory` will take precedence. Otherwise, this +# setting will be used. Typically, this setting is used only for the first +# window. +# +# The default is `inherit` except in special scenarios listed next. On macOS, +# if Ghostty can detect it is launched from launchd (double-clicked) or +# `open`, then it defaults to `home`. On Linux with GTK, if Ghostty can detect +# it was launched from a desktop launcher, then it defaults to `home`. +# +# The value of this must be an absolute value or one of the special values +# below: +# +# * `home` - The home directory of the executing user. +# +# * `inherit` - The working directory of the launching process. +working-directory = + +# Key bindings. The format is `trigger=action`. Duplicate triggers will +# overwrite previously set values. The list of actions is available in +# the documentation or using the `ghostty +list-actions` command. +# +# Trigger: `+`-separated list of keys and modifiers. Example: `ctrl+a`, +# `ctrl+shift+b`, `up`. +# +# Valid keys are currently only listed in the +# [Ghostty source code](https://github.com/ghostty-org/ghostty/blob/d6e76858164d52cff460fedc61ddf2e560912d71/src/input/key.zig#L255). +# This is a documentation limitation and we will improve this in the future. +# A common gotcha is that numeric keys are written as words: e.g. `one`, +# `two`, `three`, etc. and not `1`, `2`, `3`. This will also be improved in +# the future. +# +# Valid modifiers are `shift`, `ctrl` (alias: `control`), `alt` (alias: `opt`, +# `option`), and `super` (alias: `cmd`, `command`). You may use the modifier +# or the alias. When debugging keybinds, the non-aliased modifier will always +# be used in output. +# +# Note: The fn or "globe" key on keyboards are not supported as a +# modifier. This is a limitation of the operating systems and GUI toolkits +# that Ghostty uses. +# +# Some additional notes for triggers: +# +# * modifiers cannot repeat, `ctrl+ctrl+a` is invalid. +# +# * modifiers and keys can be in any order, `shift+a+ctrl` is *weird*, +# but valid. +# +# * only a single key input is allowed, `ctrl+a+b` is invalid. +# +# * the key input can be prefixed with `physical:` to specify a +# physical key mapping rather than a logical one. A physical key +# mapping responds to the hardware keycode and not the keycode +# translated by any system keyboard layouts. Example: "ctrl+physical:a" +# +# You may also specify multiple triggers separated by `>` to require a +# sequence of triggers to activate the action. For example, +# `ctrl+a>n=new_window` will only trigger the `new_window` action if the +# user presses `ctrl+a` followed separately by `n`. In other software, this +# is sometimes called a leader key, a key chord, a key table, etc. There +# is no hardcoded limit on the number of parts in a sequence. +# +# Warning: If you define a sequence as a CLI argument to `ghostty`, +# you probably have to quote the keybind since `>` is a special character +# in most shells. Example: ghostty --keybind='ctrl+a>n=new_window' +# +# A trigger sequence has some special handling: +# +# * Ghostty will wait an indefinite amount of time for the next key in +# the sequence. There is no way to specify a timeout. The only way to +# force the output of a prefix key is to assign another keybind to +# specifically output that key (e.g. `ctrl+a>ctrl+a=text:foo`) or +# press an unbound key which will send both keys to the program. +# +# * If a prefix in a sequence is previously bound, the sequence will +# override the previous binding. For example, if `ctrl+a` is bound to +# `new_window` and `ctrl+a>n` is bound to `new_tab`, pressing `ctrl+a` +# will do nothing. +# +# * Adding to the above, if a previously bound sequence prefix is +# used in a new, non-sequence binding, the entire previously bound +# sequence will be unbound. For example, if you bind `ctrl+a>n` and +# `ctrl+a>t`, and then bind `ctrl+a` directly, both `ctrl+a>n` and +# `ctrl+a>t` will become unbound. +# +# * Trigger sequences are not allowed for `global:` or `all:`-prefixed +# triggers. This is a limitation we could remove in the future. +# +# Action is the action to take when the trigger is satisfied. It takes the +# format `action` or `action:param`. The latter form is only valid if the +# action requires a parameter. +# +# * `ignore` - Do nothing, ignore the key input. This can be used to +# black hole certain inputs to have no effect. +# +# * `unbind` - Remove the binding. This makes it so the previous action +# is removed, and the key will be sent through to the child command +# if it is printable. Unbind will remove any matching trigger, +# including `physical:`-prefixed triggers without specifying the +# prefix. +# +# * `csi:text` - Send a CSI sequence. e.g. `csi:A` sends "cursor up". +# +# * `esc:text` - Send an escape sequence. e.g. `esc:d` deletes to the +# end of the word to the right. +# +# * `text:text` - Send a string. Uses Zig string literal syntax. +# e.g. `text:\x15` sends Ctrl-U. +# +# * All other actions can be found in the documentation or by using the +# `ghostty +list-actions` command. +# +# Some notes for the action: +# +# * The parameter is taken as-is after the `:`. Double quotes or +# other mechanisms are included and NOT parsed. If you want to +# send a string value that includes spaces, wrap the entire +# trigger/action in double quotes. Example: `--keybind="up=csi:A B"` +# +# There are some additional special values that can be specified for +# keybind: +# +# * `keybind=clear` will clear all set keybindings. Warning: this +# removes ALL keybindings up to this point, including the default +# keybindings. +# +# The keybind trigger can be prefixed with some special values to change +# the behavior of the keybind. These are: +# +# * `all:` - Make the keybind apply to all terminal surfaces. By default, +# keybinds only apply to the focused terminal surface. If this is true, +# then the keybind will be sent to all terminal surfaces. This only +# applies to actions that are surface-specific. For actions that +# are already global (e.g. `quit`), this prefix has no effect. +# +# * `global:` - Make the keybind global. By default, keybinds only work +# within Ghostty and under the right conditions (application focused, +# sometimes terminal focused, etc.). If you want a keybind to work +# globally across your system (e.g. even when Ghostty is not focused), +# specify this prefix. This prefix implies `all:`. Note: this does not +# work in all environments; see the additional notes below for more +# information. +# +# * `unconsumed:` - Do not consume the input. By default, a keybind +# will consume the input, meaning that the associated encoding (if +# any) will not be sent to the running program in the terminal. If +# you wish to send the encoded value to the program, specify the +# `unconsumed:` prefix before the entire keybind. For example: +# `unconsumed:ctrl+a=reload_config`. `global:` and `all:`-prefixed +# keybinds will always consume the input regardless of this setting. +# Since they are not associated with a specific terminal surface, +# they're never encoded. +# +# * `performable:` - Only consume the input if the action is able to be +# performed. For example, the `copy_to_clipboard` action will only +# consume the input if there is a selection to copy. If there is no +# selection, Ghostty behaves as if the keybind was not set. This has +# no effect with `global:` or `all:`-prefixed keybinds. For key +# sequences, this will reset the sequence if the action is not +# performable (acting identically to not having a keybind set at +# all). +# +# Performable keybinds will not appear as menu shortcuts in the +# application menu. This is because the menu shortcuts force the +# action to be performed regardless of the state of the terminal. +# Performable keybinds will still work, they just won't appear as +# a shortcut label in the menu. +# +# Keybind triggers are not unique per prefix combination. For example, +# `ctrl+a` and `global:ctrl+a` are not two separate keybinds. The keybind +# set later will overwrite the keybind set earlier. In this case, the +# `global:` keybind will be used. +# +# Multiple prefixes can be specified. For example, +# `global:unconsumed:ctrl+a=reload_config` will make the keybind global +# and not consume the input to reload the config. +# +# Note: `global:` is only supported on macOS. On macOS, +# this feature requires accessibility permissions to be granted to Ghostty. +# When a `global:` keybind is specified and Ghostty is launched or reloaded, +# Ghostty will attempt to request these permissions. If the permissions are +# not granted, the keybind will not work. On macOS, you can find these +# permissions in System Preferences -> Privacy & Security -> Accessibility. +keybind = super+page_up=scroll_page_up +keybind = super+ctrl+equal=equalize_splits +keybind = super+physical:four=goto_tab:4 +keybind = super+shift+down=jump_to_prompt:1 +keybind = super+shift+w=close_window +keybind = super+shift+left_bracket=previous_tab +keybind = super+backspace=text:\x15 +keybind = super+alt+w=close_tab +keybind = super+w=close_surface +keybind = super+alt+i=inspector:toggle +keybind = super+physical:eight=goto_tab:8 +keybind = super+alt+right=goto_split:right +keybind = shift+up=adjust_selection:up +keybind = super+down=jump_to_prompt:1 +keybind = super+enter=toggle_fullscreen +keybind = super+t=new_tab +keybind = super+c=copy_to_clipboard +keybind = super+shift+right_bracket=next_tab +keybind = super+physical:one=goto_tab:1 +keybind = shift+left=adjust_selection:left +keybind = super+equal=increase_font_size:1 +keybind = shift+page_up=adjust_selection:page_up +keybind = super+physical:three=goto_tab:3 +keybind = super+right=text:\x05 +keybind = super+d=new_split:right +keybind = super+ctrl+down=resize_split:down,10 +keybind = shift+end=adjust_selection:end +keybind = super+plus=increase_font_size:1 +keybind = super+q=quit +keybind = super+home=scroll_to_top +keybind = super+ctrl+left=resize_split:left,10 +keybind = alt+left=esc:b +keybind = super+ctrl+up=resize_split:up,10 +keybind = super+left=text:\x01 +keybind = super+shift+up=jump_to_prompt:-1 +keybind = shift+right=adjust_selection:right +keybind = super+comma=open_config +keybind = super+shift+comma=reload_config +keybind = super+minus=decrease_font_size:1 +keybind = shift+page_down=adjust_selection:page_down +keybind = ctrl+tab=next_tab +keybind = super+a=select_all +keybind = alt+right=esc:f +keybind = super+shift+enter=toggle_split_zoom +keybind = super+alt+down=goto_split:down +keybind = super+ctrl+f=toggle_fullscreen +keybind = super+ctrl+right=resize_split:right,10 +keybind = super+alt+shift+j=write_screen_file:open +keybind = shift+down=adjust_selection:down +keybind = ctrl+shift+tab=previous_tab +keybind = super+n=new_window +keybind = super+alt+left=goto_split:left +keybind = super+page_down=scroll_page_down +keybind = super+alt+shift+w=close_all_windows +keybind = super+alt+up=goto_split:up +keybind = super+shift+v=paste_from_selection +keybind = super+left_bracket=goto_split:previous +keybind = super+physical:nine=last_tab +keybind = super+right_bracket=goto_split:next +keybind = super+end=scroll_to_bottom +keybind = super+shift+j=write_screen_file:paste +keybind = super+shift+d=new_split:down +keybind = super+zero=reset_font_size +keybind = super+physical:five=goto_tab:5 +keybind = shift+home=adjust_selection:home +keybind = super+physical:seven=goto_tab:7 +keybind = super+up=jump_to_prompt:-1 +keybind = super+k=clear_screen +keybind = super+physical:two=goto_tab:2 +keybind = super+physical:six=goto_tab:6 +keybind = super+v=paste_from_clipboard + +# Horizontal window padding. This applies padding between the terminal cells +# and the left and right window borders. The value is in points, meaning that +# it will be scaled appropriately for screen DPI. +# +# If this value is set too large, the screen will render nothing, because the +# grid will be completely squished by the padding. It is up to you as the user +# to pick a reasonable value. If you pick an unreasonable value, a warning +# will appear in the logs. +# +# Changing this configuration at runtime will only affect new terminals, i.e. +# new windows, tabs, etc. +# +# To set a different left and right padding, specify two numerical values +# separated by a comma. For example, `window-padding-x = 2,4` will set the +# left padding to 2 and the right padding to 4. If you want to set both +# paddings to the same value, you can use a single value. For example, +# `window-padding-x = 2` will set both paddings to 2. +window-padding-x = 2 + +# Vertical window padding. This applies padding between the terminal cells and +# the top and bottom window borders. The value is in points, meaning that it +# will be scaled appropriately for screen DPI. +# +# If this value is set too large, the screen will render nothing, because the +# grid will be completely squished by the padding. It is up to you as the user +# to pick a reasonable value. If you pick an unreasonable value, a warning +# will appear in the logs. +# +# Changing this configuration at runtime will only affect new terminals, +# i.e. new windows, tabs, etc. +# +# To set a different top and bottom padding, specify two numerical values +# separated by a comma. For example, `window-padding-y = 2,4` will set the +# top padding to 2 and the bottom padding to 4. If you want to set both +# paddings to the same value, you can use a single value. For example, +# `window-padding-y = 2` will set both paddings to 2. +window-padding-y = 2 + +# The viewport dimensions are usually not perfectly divisible by the cell +# size. In this case, some extra padding on the end of a column and the bottom +# of the final row may exist. If this is `true`, then this extra padding +# is automatically balanced between all four edges to minimize imbalance on +# one side. If this is `false`, the top left grid cell will always hug the +# edge with zero padding other than what may be specified with the other +# `window-padding` options. +# +# If other `window-padding` fields are set and this is `true`, this will still +# apply. The other padding is applied first and may affect how many grid cells +# actually exist, and this is applied last in order to balance the padding +# given a certain viewport size and grid cell size. +window-padding-balance = false + +# The color of the padding area of the window. Valid values are: +# +# * `background` - The background color specified in `background`. +# * `extend` - Extend the background color of the nearest grid cell. +# * `extend-always` - Same as "extend" but always extends without applying +# any of the heuristics that disable extending noted below. +# +# The "extend" value will be disabled in certain scenarios. On primary +# screen applications (e.g. not something like Neovim), the color will not +# be extended vertically if any of the following are true: +# +# * The nearest row has any cells that have the default background color. +# The thinking is that in this case, the default background color looks +# fine as a padding color. +# * The nearest row is a prompt row (requires shell integration). The +# thinking here is that prompts often contain powerline glyphs that +# do not look good extended. +# * The nearest row contains a perfect fit powerline character. These +# don't look good extended. +# +window-padding-color = background + +# Synchronize rendering with the screen refresh rate. If true, this will +# minimize tearing and align redraws with the screen but may cause input +# latency. If false, this will maximize redraw frequency but may cause tearing, +# and under heavy load may use more CPU and power. +# +# This defaults to true because out-of-sync rendering on macOS can +# cause kernel panics (macOS 14.4+) and performance issues for external +# displays over some hardware such as DisplayLink. If you want to minimize +# input latency, set this to false with the known aforementioned risks. +# +# Changing this value at runtime will only affect new terminals. +# +# This setting is only supported currently on macOS. +window-vsync = true + +# If true, new windows and tabs will inherit the working directory of the +# previously focused window. If no window was previously focused, the default +# working directory will be used (the `working-directory` option). +window-inherit-working-directory = true + +# If true, new windows and tabs will inherit the font size of the previously +# focused window. If no window was previously focused, the default font size +# will be used. If this is false, the default font size specified in the +# configuration `font-size` will be used. +window-inherit-font-size = true + +# Configure a preference for window decorations. This setting specifies +# a _preference_; the actual OS, desktop environment, window manager, etc. +# may override this preference. Ghostty will do its best to respect this +# preference but it may not always be possible. +# +# Valid values: +# +# * `none` - All window decorations will be disabled. Titlebar, +# borders, etc. will not be shown. On macOS, this will also disable +# tabs (enforced by the system). +# +# * `auto` - Automatically decide to use either client-side or server-side +# decorations based on the detected preferences of the current OS and +# desktop environment. This option usually makes Ghostty look the most +# "native" for your desktop. +# +# * `client` - Prefer client-side decorations. +# +# * `server` - Prefer server-side decorations. This is only relevant +# on Linux with GTK, either on X11, or Wayland on a compositor that +# supports the `org_kde_kwin_server_decoration` protocol (e.g. KDE Plasma, +# but almost any non-GNOME desktop supports this protocol). +# +# If `server` is set but the environment doesn't support server-side +# decorations, client-side decorations will be used instead. +# +# The default value is `auto`. +# +# For the sake of backwards compatibility and convenience, this setting also +# accepts boolean true and false values. If set to `true`, this is equivalent +# to `auto`. If set to `false`, this is equivalent to `none`. +# This is convenient for users who live primarily on systems that don't +# differentiate between client and server-side decorations (e.g. macOS and +# Windows). +# +# The "toggle_window_decorations" keybind action can be used to create +# a keybinding to toggle this setting at runtime. This will always toggle +# back to "auto" if the current value is "none" (this is an issue +# that will be fixed in the future). +# +# Changing this configuration in your configuration and reloading will +# only affect new windows. Existing windows will not be affected. +# +# macOS: To hide the titlebar without removing the native window borders +# or rounded corners, use `macos-titlebar-style = hidden` instead. +window-decoration = auto + +# The font that will be used for the application's window and tab titles. +# +# If this setting is left unset, the system default font will be used. +# +# Note: any font available on the system may be used, this font is not +# required to be a fixed-width font. +window-title-font-family = + +# The text that will be displayed in the subtitle of the window. Valid values: +# +# * `false` - Disable the subtitle. +# * `working-directory` - Set the subtitle to the working directory of the +# surface. +# +# This feature is only supported on GTK with Adwaita enabled. +window-subtitle = false + +# The theme to use for the windows. Valid values: +# +# * `auto` - Determine the theme based on the configured terminal +# background color. This has no effect if the "theme" configuration +# has separate light and dark themes. In that case, the behavior +# of "auto" is equivalent to "system". +# * `system` - Use the system theme. +# * `light` - Use the light theme regardless of system theme. +# * `dark` - Use the dark theme regardless of system theme. +# * `ghostty` - Use the background and foreground colors specified in the +# Ghostty configuration. This is only supported on Linux builds with +# Adwaita and `gtk-adwaita` enabled. +# +# On macOS, if `macos-titlebar-style` is "tabs", the window theme will be +# automatically set based on the luminosity of the terminal background color. +# This only applies to terminal windows. This setting will still apply to +# non-terminal windows within Ghostty. +# +# This is currently only supported on macOS and Linux. +window-theme = auto + +# The color space to use when interpreting terminal colors. "Terminal colors" +# refers to colors specified in your configuration and colors produced by +# direct-color SGR sequences. +# +# Valid values: +# +# * `srgb` - Interpret colors in the sRGB color space. This is the default. +# * `display-p3` - Interpret colors in the Display P3 color space. +# +# This setting is currently only supported on macOS. +window-colorspace = srgb + +# The initial window size. This size is in terminal grid cells by default. +# Both values must be set to take effect. If only one value is set, it is +# ignored. +# +# We don't currently support specifying a size in pixels but a future change +# can enable that. If this isn't specified, the app runtime will determine +# some default size. +# +# Note that the window manager may put limits on the size or override the +# size. For example, a tiling window manager may force the window to be a +# certain size to fit within the grid. There is nothing Ghostty will do about +# this, but it will make an effort. +# +# Sizes larger than the screen size will be clamped to the screen size. +# This can be used to create a maximized-by-default window size. +# +# This will not affect new tabs, splits, or other nested terminal elements. +# This only affects the initial window size of any new window. Changing this +# value will not affect the size of the window after it has been created. This +# is only used for the initial size. +# +# BUG: On Linux with GTK, the calculated window size will not properly take +# into account window decorations. As a result, the grid dimensions will not +# exactly match this configuration. If window decorations are disabled (see +# `window-decoration`), then this will work as expected. +# +# Windows smaller than 10 wide by 4 high are not allowed. +window-height = 0 + +window-width = 0 +# The starting window position. This position is in pixels and is relative +# to the top-left corner of the primary monitor. Both values must be set to take +# effect. If only one value is set, it is ignored. +# +# Note that the window manager may put limits on the position or override +# the position. For example, a tiling window manager may force the window +# to be a certain position to fit within the grid. There is nothing Ghostty +# will do about this, but it will make an effort. +# +# Also note that negative values are also up to the operating system and +# window manager. Some window managers may not allow windows to be placed +# off-screen. +# +# Invalid positions are runtime-specific, but generally the positions are +# clamped to the nearest valid position. +# +# On macOS, the window position is relative to the top-left corner of +# the visible screen area. This means that if the menu bar is visible, the +# window will be placed below the menu bar. +# +# Note: this is only supported on macOS and Linux GLFW builds. The GTK +# runtime does not support setting the window position (this is a limitation +# of GTK 4.0). +window-position-x = + +window-position-y = +# Whether to enable saving and restoring window state. Window state includes +# their position, size, tabs, splits, etc. Some window state requires shell +# integration, such as preserving working directories. See `shell-integration` +# for more information. +# +# There are three valid values for this configuration: +# +# * `default` will use the default system behavior. On macOS, this +# will only save state if the application is forcibly terminated +# or if it is configured systemwide via Settings.app. +# +# * `never` will never save window state. +# +# * `always` will always save window state whenever Ghostty is exited. +# +# If you change this value to `never` while Ghostty is not running, the next +# Ghostty launch will NOT restore the window state. +# +# If you change this value to `default` while Ghostty is not running and the +# previous exit saved state, the next Ghostty launch will still restore the +# window state. This is because Ghostty cannot know if the previous exit was +# due to a forced save or not (macOS doesn't provide this information). +# +# If you change this value so that window state is saved while Ghostty is not +# running, the previous window state will not be restored because Ghostty only +# saves state on exit if this is enabled. +# +# The default value is `default`. +# +# This is currently only supported on macOS. This has no effect on Linux. +window-save-state = default + +# Resize the window in discrete increments of the focused surface's cell size. +# If this is disabled, surfaces are resized in pixel increments. Currently +# only supported on macOS. +window-step-resize = false + +# The position where new tabs are created. Valid values: +# +# * `current` - Insert the new tab after the currently focused tab, +# or at the end if there are no focused tabs. +# +# * `end` - Insert the new tab at the end of the tab list. +window-new-tab-position = current + +# Background color for the window titlebar. This only takes effect if +# window-theme is set to ghostty. Currently only supported in the GTK app +# runtime. +# +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +window-titlebar-background = + +# Foreground color for the window titlebar. This only takes effect if +# window-theme is set to ghostty. Currently only supported in the GTK app +# runtime. +# +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +window-titlebar-foreground = + +# This controls when resize overlays are shown. Resize overlays are a +# transient popup that shows the size of the terminal while the surfaces are +# being resized. The possible options are: +# +# * `always` - Always show resize overlays. +# * `never` - Never show resize overlays. +# * `after-first` - The resize overlay will not appear when the surface +# is first created, but will show up if the surface is +# subsequently resized. +# +# The default is `after-first`. +resize-overlay = after-first + +# If resize overlays are enabled, this controls the position of the overlay. +# The possible options are: +# +# * `center` +# * `top-left` +# * `top-center` +# * `top-right` +# * `bottom-left` +# * `bottom-center` +# * `bottom-right` +# +# The default is `center`. +resize-overlay-position = center + +# If resize overlays are enabled, this controls how long the overlay is +# visible on the screen before it is hidden. The default is ¾ of a second or +# 750 ms. +# +# The duration is specified as a series of numbers followed by time units. +# Whitespace is allowed between numbers and units. Each number and unit will +# be added together to form the total duration. +# +# The allowed time units are as follows: +# +# * `y` - 365 SI days, or 8760 hours, or 31536000 seconds. No adjustments +# are made for leap years or leap seconds. +# * `d` - one SI day, or 86400 seconds. +# * `h` - one hour, or 3600 seconds. +# * `m` - one minute, or 60 seconds. +# * `s` - one second. +# * `ms` - one millisecond, or 0.001 second. +# * `us` or `µs` - one microsecond, or 0.000001 second. +# * `ns` - one nanosecond, or 0.000000001 second. +# +# Examples: +# * `1h30m` +# * `45s` +# +# Units can be repeated and will be added together. This means that +# `1h1h` is equivalent to `2h`. This is confusing and should be avoided. +# A future update may disallow this. +# +# The maximum value is `584y 49w 23h 34m 33s 709ms 551µs 615ns`. Any +# value larger than this will be clamped to the maximum value. +resize-overlay-duration = 750ms + +# If true, when there are multiple split panes, the mouse selects the pane +# that is focused. This only applies to the currently focused window; e.g. +# mousing over a split in an unfocused window will not focus that split +# and bring the window to front. +# +# Default is false. +focus-follows-mouse = false + +# Whether to allow programs running in the terminal to read/write to the +# system clipboard (OSC 52, for googling). The default is to allow clipboard +# reading after prompting the user and allow writing unconditionally. +# +# Valid values are: +# +# * `ask` +# * `allow` +# * `deny` +# +clipboard-read = ask + +clipboard-write = allow +# Trims trailing whitespace on data that is copied to the clipboard. This does +# not affect data sent to the clipboard via `clipboard-write`. +clipboard-trim-trailing-spaces = true + +# Require confirmation before pasting text that appears unsafe. This helps +# prevent a "copy/paste attack" where a user may accidentally execute unsafe +# commands by pasting text with newlines. +clipboard-paste-protection = true + +# If true, bracketed pastes will be considered safe. By default, bracketed +# pastes are considered safe. "Bracketed" pastes are pastes while the running +# program has bracketed paste mode enabled (a setting set by the running +# program, not the terminal emulator). +clipboard-paste-bracketed-safe = true + +# Enables or disabled title reporting (CSI 21 t). This escape sequence +# allows the running program to query the terminal title. This is a common +# security issue and is disabled by default. +# +# Warning: This can expose sensitive information at best and enable +# arbitrary code execution at worst (with a maliciously crafted title +# and a minor amount of user interaction). +title-report = false + +# The total amount of bytes that can be used for image data (e.g. the Kitty +# image protocol) per terminal screen. The maximum value is 4,294,967,295 +# (4GiB). The default is 320MB. If this is set to zero, then all image +# protocols will be disabled. +# +# This value is separate for primary and alternate screens so the effective +# limit per surface is double. +image-storage-limit = 320000000 + +# Whether to automatically copy selected text to the clipboard. `true` +# will prefer to copy to the selection clipboard, otherwise it will copy to +# the system clipboard. +# +# The value `clipboard` will always copy text to the selection clipboard +# as well as the system clipboard. +# +# Middle-click paste will always use the selection clipboard. Middle-click +# paste is always enabled even if this is `false`. +# +# The default value is true on Linux and macOS. +copy-on-select = true + +# The time in milliseconds between clicks to consider a click a repeat +# (double, triple, etc.) or an entirely new single click. A value of zero will +# use a platform-specific default. The default on macOS is determined by the +# OS settings. On every other platform it is 500ms. +click-repeat-interval = 0 + +# Additional configuration files to read. This configuration can be repeated +# to read multiple configuration files. Configuration files themselves can +# load more configuration files. Paths are relative to the file containing the +# `config-file` directive. For command-line arguments, paths are relative to +# the current working directory. +# +# Prepend a ? character to the file path to suppress errors if the file does +# not exist. If you want to include a file that begins with a literal ? +# character, surround the file path in double quotes ("). +# +# Cycles are not allowed. If a cycle is detected, an error will be logged and +# the configuration file will be ignored. +# +# Configuration files are loaded after the configuration they're defined +# within in the order they're defined. **THIS IS A VERY SUBTLE BUT IMPORTANT +# POINT.** To put it another way: configuration files do not take effect +# until after the entire configuration is loaded. For example, in the +# configuration below: +# +# ``` +# config-file = "foo" +# a = 1 +# ``` +# +# If "foo" contains `a = 2`, the final value of `a` will be 2, because +# `foo` is loaded after the configuration file that configures the +# nested `config-file` value. +config-file = + +# When this is true, the default configuration file paths will be loaded. +# The default configuration file paths are currently only the XDG +# config path ($XDG_CONFIG_HOME/ghostty/config). +# +# If this is false, the default configuration paths will not be loaded. +# This is targeted directly at using Ghostty from the CLI in a way +# that minimizes external effects. +# +# This is a CLI-only configuration. Setting this in a configuration file +# will have no effect. It is not an error, but it will not do anything. +# This configuration can only be set via CLI arguments. +config-default-files = true + +# Confirms that a surface should be closed before closing it. +# +# This defaults to `true`. If set to `false`, surfaces will close without +# any confirmation. This can also be set to `always`, which will always +# confirm closing a surface, even if shell integration says a process isn't +# running. +confirm-close-surface = true + +# Whether or not to quit after the last surface is closed. +# +# This defaults to `false` on macOS since that is standard behavior for +# a macOS application. On Linux, this defaults to `true` since that is +# generally expected behavior. +# +# On Linux, if this is `true`, Ghostty can delay quitting fully until a +# configurable amount of time has passed after the last window is closed. +# See the documentation of `quit-after-last-window-closed-delay`. +quit-after-last-window-closed = false + +# Controls how long Ghostty will stay running after the last open surface has +# been closed. This only has an effect if `quit-after-last-window-closed` is +# also set to `true`. +# +# The minimum value for this configuration is `1s`. Any values lower than +# this will be clamped to `1s`. +# +# The duration is specified as a series of numbers followed by time units. +# Whitespace is allowed between numbers and units. Each number and unit will +# be added together to form the total duration. +# +# The allowed time units are as follows: +# +# * `y` - 365 SI days, or 8760 hours, or 31536000 seconds. No adjustments +# are made for leap years or leap seconds. +# * `d` - one SI day, or 86400 seconds. +# * `h` - one hour, or 3600 seconds. +# * `m` - one minute, or 60 seconds. +# * `s` - one second. +# * `ms` - one millisecond, or 0.001 second. +# * `us` or `µs` - one microsecond, or 0.000001 second. +# * `ns` - one nanosecond, or 0.000000001 second. +# +# Examples: +# * `1h30m` +# * `45s` +# +# Units can be repeated and will be added together. This means that +# `1h1h` is equivalent to `2h`. This is confusing and should be avoided. +# A future update may disallow this. +# +# The maximum value is `584y 49w 23h 34m 33s 709ms 551µs 615ns`. Any +# value larger than this will be clamped to the maximum value. +# +# By default `quit-after-last-window-closed-delay` is unset and +# Ghostty will quit immediately after the last window is closed if +# `quit-after-last-window-closed` is `true`. +# +# Only implemented on Linux. +quit-after-last-window-closed-delay = + +# This controls whether an initial window is created when Ghostty +# is run. Note that if `quit-after-last-window-closed` is `true` and +# `quit-after-last-window-closed-delay` is set, setting `initial-window` to +# `false` will mean that Ghostty will quit after the configured delay if no +# window is ever created. Only implemented on Linux and macOS. +initial-window = true + +# The position of the "quick" terminal window. To learn more about the +# quick terminal, see the documentation for the `toggle_quick_terminal` +# binding action. +# +# Valid values are: +# +# * `top` - Terminal appears at the top of the screen. +# * `bottom` - Terminal appears at the bottom of the screen. +# * `left` - Terminal appears at the left of the screen. +# * `right` - Terminal appears at the right of the screen. +# * `center` - Terminal appears at the center of the screen. +# +# Changing this configuration requires restarting Ghostty completely. +# +# Note: There is no default keybind for toggling the quick terminal. +# To enable this feature, bind the `toggle_quick_terminal` action to a key. +quick-terminal-position = top + +# The screen where the quick terminal should show up. +# +# Valid values are: +# +# * `main` - The screen that the operating system recommends as the main +# screen. On macOS, this is the screen that is currently receiving +# keyboard input. This screen is defined by the operating system and +# not chosen by Ghostty. +# +# * `mouse` - The screen that the mouse is currently hovered over. +# +# * `macos-menu-bar` - The screen that contains the macOS menu bar as +# set in the display settings on macOS. This is a bit confusing because +# every screen on macOS has a menu bar, but this is the screen that +# contains the primary menu bar. +# +# The default value is `main` because this is the recommended screen +# by the operating system. +quick-terminal-screen = main + +# Duration (in seconds) of the quick terminal enter and exit animation. +# Set it to 0 to disable animation completely. This can be changed at +# runtime. +quick-terminal-animation-duration = 0.2 + +# Automatically hide the quick terminal when focus shifts to another window. +# Set it to false for the quick terminal to remain open even when it loses focus. +quick-terminal-autohide = true + +# This configuration option determines the behavior of the quick terminal +# when switching between macOS spaces. macOS spaces are virtual desktops +# that can be manually created or are automatically created when an +# application is in full-screen mode. +# +# Valid values are: +# +# * `move` - When switching to another space, the quick terminal will +# also moved to the current space. +# +# * `remain` - The quick terminal will stay only in the space where it +# was originally opened and will not follow when switching to another +# space. +# +# The default value is `move`. +quick-terminal-space-behavior = move + +# Whether to enable shell integration auto-injection or not. Shell integration +# greatly enhances the terminal experience by enabling a number of features: +# +# * Working directory reporting so new tabs, splits inherit the +# previous terminal's working directory. +# +# * Prompt marking that enables the "jump_to_prompt" keybinding. +# +# * If you're sitting at a prompt, closing a terminal will not ask +# for confirmation. +# +# * Resizing the window with a complex prompt usually paints much +# better. +# +# Allowable values are: +# +# * `none` - Do not do any automatic injection. You can still manually +# configure your shell to enable the integration. +# +# * `detect` - Detect the shell based on the filename. +# +# * `bash`, `elvish`, `fish`, `zsh` - Use this specific shell injection scheme. +# +# The default value is `detect`. +shell-integration = detect + +# Shell integration features to enable. These require our shell integration +# to be loaded, either automatically via shell-integration or manually. +# +# The format of this is a list of features to enable separated by commas. If +# you prefix a feature with `no-` then it is disabled. If you omit a feature, +# its default value is used, so you must explicitly disable features you don't +# want. You can also use `true` or `false` to turn all features on or off. +# +# Available features: +# +# * `cursor` - Set the cursor to a blinking bar at the prompt. +# +# * `sudo` - Set sudo wrapper to preserve terminfo. +# +# * `title` - Set the window title via shell integration. +# +# Example: `cursor`, `no-cursor`, `sudo`, `no-sudo`, `title`, `no-title` +shell-integration-features = cursor,no-sudo,title + +# Sets the reporting format for OSC sequences that request color information. +# Ghostty currently supports OSC 10 (foreground), OSC 11 (background), and +# OSC 4 (256 color palette) queries, and by default the reported values +# are scaled-up RGB values, where each component are 16 bits. This is how +# most terminals report these values. However, some legacy applications may +# require 8-bit, unscaled, components. We also support turning off reporting +# altogether. The components are lowercase hex values. +# +# Allowable values are: +# +# * `none` - OSC 4/10/11 queries receive no reply +# +# * `8-bit` - Color components are return unscaled, e.g. `rr/gg/bb` +# +# * `16-bit` - Color components are returned scaled, e.g. `rrrr/gggg/bbbb` +# +# The default value is `16-bit`. +osc-color-report-format = 16-bit + +# If true, allows the "KAM" mode (ANSI mode 2) to be used within +# the terminal. KAM disables keyboard input at the request of the +# application. This is not a common feature and is not recommended +# to be enabled. This will not be documented further because +# if you know you need KAM, you know. If you don't know if you +# need KAM, you don't need it. +vt-kam-allowed = false + +# Custom shaders to run after the default shaders. This is a file path +# to a GLSL-syntax shader for all platforms. +# +# Warning: Invalid shaders can cause Ghostty to become unusable such as by +# causing the window to be completely black. If this happens, you can +# unset this configuration to disable the shader. +# +# On Linux, this requires OpenGL 4.2. Ghostty typically only requires +# OpenGL 3.3, but custom shaders push that requirement up to 4.2. +# +# The shader API is identical to the Shadertoy API: you specify a `mainImage` +# function and the available uniforms match Shadertoy. The iChannel0 uniform +# is a texture containing the rendered terminal screen. +# +# If the shader fails to compile, the shader will be ignored. Any errors +# related to shader compilation will not show up as configuration errors +# and only show up in the log, since shader compilation happens after +# configuration loading on the dedicated render thread. For interactive +# development, use [shadertoy.com](https://shadertoy.com). +# +# This can be repeated multiple times to load multiple shaders. The shaders +# will be run in the order they are specified. +# +# Changing this value at runtime and reloading the configuration will only +# affect new windows, tabs, and splits. +custom-shader = + +# If `true` (default), the focused terminal surface will run an animation +# loop when custom shaders are used. This uses slightly more CPU (generally +# less than 10%) but allows the shader to animate. This only runs if there +# are custom shaders and the terminal is focused. +# +# If this is set to `false`, the terminal and custom shader will only render +# when the terminal is updated. This is more efficient but the shader will +# not animate. +# +# This can also be set to `always`, which will always run the animation +# loop regardless of whether the terminal is focused or not. The animation +# loop will still only run when custom shaders are used. Note that this +# will use more CPU per terminal surface and can become quite expensive +# depending on the shader and your terminal usage. +# +# This value can be changed at runtime and will affect all currently +# open terminals. +custom-shader-animation = true + +# Control the in-app notifications that Ghostty shows. +# +# On Linux (GTK) with Adwaita, in-app notifications show up as toasts. Toasts +# appear overlaid on top of the terminal window. They are used to show +# information that is not critical but may be important. +# +# Possible notifications are: +# +# - `clipboard-copy` (default: true) - Show a notification when text is copied +# to the clipboard. +# +# To specify a notification to enable, specify the name of the notification. +# To specify a notification to disable, prefix the name with `no-`. For +# example, to disable `clipboard-copy`, set this configuration to +# `no-clipboard-copy`. To enable it, set this configuration to `clipboard-copy`. +# +# Multiple notifications can be enabled or disabled by separating them +# with a comma. +# +# A value of "false" will disable all notifications. A value of "true" will +# enable all notifications. +# +# This configuration only applies to GTK with Adwaita enabled. +app-notifications = clipboard-copy + +# If anything other than false, fullscreen mode on macOS will not use the +# native fullscreen, but make the window fullscreen without animations and +# using a new space. It's faster than the native fullscreen mode since it +# doesn't use animations. +# +# Important: tabs DO NOT WORK in this mode. Non-native fullscreen removes +# the titlebar and macOS native tabs require the titlebar. If you use tabs, +# you should not use this mode. +# +# If you fullscreen a window with tabs, the currently focused tab will +# become fullscreen while the others will remain in a separate window in +# the background. You can switch to that window using normal window-switching +# keybindings such as command+tilde. When you exit fullscreen, the window +# will return to the tabbed state it was in before. +# +# Allowable values are: +# +# * `visible-menu` - Use non-native macOS fullscreen, keep the menu bar visible +# * `true` - Use non-native macOS fullscreen, hide the menu bar +# * `false` - Use native macOS fullscreen +# +# Changing this option at runtime works, but will only apply to the next +# time the window is made fullscreen. If a window is already fullscreen, +# it will retain the previous setting until fullscreen is exited. +macos-non-native-fullscreen = false + +# The style of the macOS titlebar. Available values are: "native", +# "transparent", "tabs", and "hidden". +# +# The "native" style uses the native macOS titlebar with zero customization. +# The titlebar will match your window theme (see `window-theme`). +# +# The "transparent" style is the same as "native" but the titlebar will +# be transparent and allow your window background color to come through. +# This makes a more seamless window appearance but looks a little less +# typical for a macOS application and may not work well with all themes. +# +# The "transparent" style will also update in real-time to dynamic +# changes to the window background color, e.g. via OSC 11. To make this +# more aesthetically pleasing, this only happens if the terminal is +# a window, tab, or split that borders the top of the window. This +# avoids a disjointed appearance where the titlebar color changes +# but all the topmost terminals don't match. +# +# The "tabs" style is a completely custom titlebar that integrates the +# tab bar into the titlebar. This titlebar always matches the background +# color of the terminal. There are some limitations to this style: +# On macOS 13 and below, saved window state will not restore tabs correctly. +# macOS 14 does not have this issue and any other macOS version has not +# been tested. +# +# The "hidden" style hides the titlebar. Unlike `window-decoration = false`, +# however, it does not remove the frame from the window or cause it to have +# squared corners. Changing to or from this option at run-time may affect +# existing windows in buggy ways. +# +# When "hidden", the top titlebar area can no longer be used for dragging +# the window. To drag the window, you can use option+click on the resizable +# areas of the frame to drag the window. This is a standard macOS behavior +# and not something Ghostty enables. +# +# The default value is "transparent". This is an opinionated choice +# but its one I think is the most aesthetically pleasing and works in +# most cases. +# +# Changing this option at runtime only applies to new windows. +macos-titlebar-style = transparent + +# Whether the proxy icon in the macOS titlebar is visible. The proxy icon +# is the icon that represents the folder of the current working directory. +# You can see this very clearly in the macOS built-in Terminal.app +# titlebar. +# +# The proxy icon is only visible with the native macOS titlebar style. +# +# Valid values are: +# +# * `visible` - Show the proxy icon. +# * `hidden` - Hide the proxy icon. +# +# The default value is `visible`. +# +# This setting can be changed at runtime and will affect all currently +# open windows but only after their working directory changes again. +# Therefore, to make this work after changing the setting, you must +# usually `cd` to a different directory, open a different file in an +# editor, etc. +macos-titlebar-proxy-icon = visible + +# macOS doesn't have a distinct "alt" key and instead has the "option" +# key which behaves slightly differently. On macOS by default, the +# option key plus a character will sometimes produces a Unicode character. +# For example, on US standard layouts option-b produces "∫". This may be +# undesirable if you want to use "option" as an "alt" key for keybindings +# in terminal programs or shells. +# +# This configuration lets you change the behavior so that option is treated +# as alt. +# +# The default behavior (unset) will depend on your active keyboard +# layout. If your keyboard layout is one of the keyboard layouts listed +# below, then the default value is "true". Otherwise, the default +# value is "false". Keyboard layouts with a default value of "true" are: +# +# - U.S. Standard +# - U.S. International +# +# Note that if an *Option*-sequence doesn't produce a printable character, it +# will be treated as *Alt* regardless of this setting. (e.g. `alt+ctrl+a`). +# +# Explicit values that can be set: +# +# If `true`, the *Option* key will be treated as *Alt*. This makes terminal +# sequences expecting *Alt* to work properly, but will break Unicode input +# sequences on macOS if you use them via the *Alt* key. +# +# You may set this to `false` to restore the macOS *Alt* key unicode +# sequences but this will break terminal sequences expecting *Alt* to work. +# +# The values `left` or `right` enable this for the left or right *Option* +# key, respectively. +# +# This does not work with GLFW builds. +macos-option-as-alt = + +# Whether to enable the macOS window shadow. The default value is true. +# With some window managers and window transparency settings, you may +# find false more visually appealing. +macos-window-shadow = true + +# If true, Ghostty on macOS will automatically enable the "Secure Input" +# feature when it detects that a password prompt is being displayed. +# +# "Secure Input" is a macOS security feature that prevents applications from +# reading keyboard events. This can always be enabled manually using the +# `Ghostty > Secure Keyboard Entry` menu item. +# +# Note that automatic password prompt detection is based on heuristics +# and may not always work as expected. Specifically, it does not work +# over SSH connections, but there may be other cases where it also +# doesn't work. +# +# A reason to disable this feature is if you find that it is interfering +# with legitimate accessibility software (or software that uses the +# accessibility APIs), since secure input prevents any application from +# reading keyboard events. +macos-auto-secure-input = true + +# If true, Ghostty will show a graphical indication when secure input is +# enabled. This indication is generally recommended to know when secure input +# is enabled. +# +# Normally, secure input is only active when a password prompt is displayed +# or it is manually (and typically temporarily) enabled. However, if you +# always have secure input enabled, the indication can be distracting and +# you may want to disable it. +macos-secure-input-indication = true + +# Customize the macOS app icon. +# +# This only affects the icon that appears in the dock, application +# switcher, etc. This does not affect the icon in Finder because +# that is controlled by a hardcoded value in the signed application +# bundle and can't be changed at runtime. For more details on what +# exactly is affected, see the `NSApplication.icon` Apple documentation; +# that is the API that is being used to set the icon. +# +# Valid values: +# +# * `official` - Use the official Ghostty icon. +# * `blueprint`, `chalkboard`, `microchip`, `glass`, `holographic`, +# `paper`, `retro`, `xray` - Official variants of the Ghostty icon +# hand-created by artists (no AI). +# * `custom-style` - Use the official Ghostty icon but with custom +# styles applied to various layers. The custom styles must be +# specified using the additional `macos-icon`-prefixed configurations. +# The `macos-icon-ghost-color` and `macos-icon-screen-color` +# configurations are required for this style. +# +# WARNING: The `custom-style` option is _experimental_. We may change +# the format of the custom styles in the future. We're still finalizing +# the exact layers and customization options that will be available. +# +# Other caveats: +# +# * The icon in the update dialog will always be the official icon. +# This is because the update dialog is managed through a +# separate framework and cannot be customized without significant +# effort. +# +macos-icon = official + +# The material to use for the frame of the macOS app icon. +# +# Valid values: +# +# * `aluminum` - A brushed aluminum frame. This is the default. +# * `beige` - A classic 90's computer beige frame. +# * `plastic` - A glossy, dark plastic frame. +# * `chrome` - A shiny chrome frame. +# +# This only has an effect when `macos-icon` is set to `custom-style`. +macos-icon-frame = aluminum + +# The color of the ghost in the macOS app icon. +# +# Note: This configuration is required when `macos-icon` is set to +# `custom-style`. +# +# This only has an effect when `macos-icon` is set to `custom-style`. +# +# Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. +macos-icon-ghost-color = + +# The color of the screen in the macOS app icon. +# +# The screen is a gradient so you can specify multiple colors that +# make up the gradient. Comma-separated colors may be specified as +# as either hex (`#RRGGBB` or `RRGGBB`) or as named X11 colors. +# +# Note: This configuration is required when `macos-icon` is set to +# `custom-style`. +# +# This only has an effect when `macos-icon` is set to `custom-style`. +macos-icon-screen-color = + +# Put every surface (tab, split, window) into a dedicated Linux cgroup. +# +# This makes it so that resource management can be done on a per-surface +# granularity. For example, if a shell program is using too much memory, +# only that shell will be killed by the oom monitor instead of the entire +# Ghostty process. Similarly, if a shell program is using too much CPU, +# only that surface will be CPU-throttled. +# +# This will cause startup times to be slower (a hundred milliseconds or so), +# so the default value is "single-instance." In single-instance mode, only +# one instance of Ghostty is running (see gtk-single-instance) so the startup +# time is a one-time cost. Additionally, single instance Ghostty is much +# more likely to have many windows, tabs, etc. so cgroup isolation is a +# big benefit. +# +# This feature requires systemd. If systemd is unavailable, cgroup +# initialization will fail. By default, this will not prevent Ghostty +# from working (see linux-cgroup-hard-fail). +# +# Valid values are: +# +# * `never` - Never use cgroups. +# * `always` - Always use cgroups. +# * `single-instance` - Enable cgroups only for Ghostty instances launched +# as single-instance applications (see gtk-single-instance). +# +linux-cgroup = single-instance + +# Memory limit for any individual terminal process (tab, split, window, +# etc.) in bytes. If this is unset then no memory limit will be set. +# +# Note that this sets the "memory.high" configuration for the memory +# controller, which is a soft limit. You should configure something like +# systemd-oom to handle killing processes that have too much memory +# pressure. +linux-cgroup-memory-limit = + +# Number of processes limit for any individual terminal process (tab, split, +# window, etc.). If this is unset then no limit will be set. +# +# Note that this sets the "pids.max" configuration for the process number +# controller, which is a hard limit. +linux-cgroup-processes-limit = + +# If this is false, then any cgroup initialization (for linux-cgroup) +# will be allowed to fail and the failure is ignored. This is useful if +# you view cgroup isolation as a "nice to have" and not a critical resource +# management feature, because Ghostty startup will not fail if cgroup APIs +# fail. +# +# If this is true, then any cgroup initialization failure will cause +# Ghostty to exit or new surfaces to not be created. +# +# Note: This currently only affects cgroup initialization. Subprocesses +# must always be able to move themselves into an isolated cgroup. +linux-cgroup-hard-fail = false + +# Enable or disable GTK's OpenGL debugging logs. The default is `true` for +# debug builds, `false` for all others. +gtk-opengl-debug = false + +# Obsolete configuration that should not be set. This was deprecated in +# Ghostty 1.1.3 and no longer has any effect. The configuration key will +# be fully removed in 1.2.0. You can manually override the GSK renderer +# using standard environment variables such as `GSK_RENDERER` (from GTK). +gtk-gsk-renderer = default + +# If `true`, the Ghostty GTK application will run in single-instance mode: +# each new `ghostty` process launched will result in a new window if there is +# already a running process. +# +# If `false`, each new ghostty process will launch a separate application. +# +# The default value is `desktop` which will default to `true` if Ghostty +# detects that it was launched from the `.desktop` file such as an app +# launcher (like Gnome Shell) or by D-Bus activation. If Ghostty is launched +# from the command line, it will default to `false`. +# +# Note that debug builds of Ghostty have a separate single-instance ID +# so you can test single instance without conflicting with release builds. +gtk-single-instance = desktop + +# When enabled, the full GTK titlebar is displayed instead of your window +# manager's simple titlebar. The behavior of this option will vary with your +# window manager. +# +# This option does nothing when `window-decoration` is false or when running +# under macOS. +# +# Changing this value at runtime and reloading the configuration will only +# affect new windows. +gtk-titlebar = true + +# Determines the side of the screen that the GTK tab bar will stick to. +# Top, bottom, left, right, and hidden are supported. The default is top. +# +# If this option has value `left` or `right` when using Adwaita, it falls +# back to `top`. `hidden`, meaning that tabs don't exist, is not supported +# without using Adwaita, falling back to `top`. +# +# When `hidden` is set and Adwaita is enabled, a tab button displaying the +# number of tabs will appear in the title bar. It has the ability to open a +# tab overview for displaying tabs. Alternatively, you can use the +# `toggle_tab_overview` action in a keybind if your window doesn't have a +# title bar, or you can switch tabs with keybinds. +gtk-tabs-location = top + +# If this is `true`, the titlebar will be hidden when the window is maximized, +# and shown when the titlebar is unmaximized. GTK only. +gtk-titlebar-hide-when-maximized = false + +# Determines the appearance of the top and bottom bars when using the +# Adwaita tab bar. This requires `gtk-adwaita` to be enabled (it is +# by default). +# +# Valid values are: +# +# * `flat` - Top and bottom bars are flat with the terminal window. +# * `raised` - Top and bottom bars cast a shadow on the terminal area. +# * `raised-border` - Similar to `raised` but the shadow is replaced with a +# more subtle border. +# +# Changing this value at runtime will only affect new windows. +adw-toolbar-style = raised + +# If `true` (default), then the Ghostty GTK tabs will be "wide." Wide tabs +# are the new typical Gnome style where tabs fill their available space. +# If you set this to `false` then tabs will only take up space they need, +# which is the old style. +gtk-wide-tabs = true + +# If `true` (default), Ghostty will enable Adwaita theme support. This +# will make `window-theme` work properly and will also allow Ghostty to +# properly respond to system theme changes, light/dark mode changing, etc. +# This requires a GTK4 desktop with a GTK4 theme. +# +# If you are running GTK3 or have a GTK3 theme, you may have to set this +# to false to get your theme picked up properly. Having this set to true +# with GTK3 should not cause any problems, but it may not work exactly as +# expected. +# +# This configuration only has an effect if Ghostty was built with +# Adwaita support. +gtk-adwaita = true + +# Custom CSS files to be loaded. +# +# This configuration can be repeated multiple times to load multiple files. +# Prepend a ? character to the file path to suppress errors if the file does +# not exist. If you want to include a file that begins with a literal ? +# character, surround the file path in double quotes ("). +# The file size limit for a single stylesheet is 5MiB. +gtk-custom-css = + +# If `true` (default), applications running in the terminal can show desktop +# notifications using certain escape sequences such as OSC 9 or OSC 777. +desktop-notifications = true + +# If `true`, the bold text will use the bright color palette. +bold-is-bright = false + +# This will be used to set the `TERM` environment variable. +# HACK: We set this with an `xterm` prefix because vim uses that to enable key +# protocols (specifically this will enable `modifyOtherKeys`), among other +# features. An option exists in vim to modify this: `:set +# keyprotocol=ghostty:kitty`, however a bug in the implementation prevents it +# from working properly. https://github.com/vim/vim/pull/13211 fixes this. +term = xterm-ghostty + +# String to send when we receive `ENQ` (`0x05`) from the command that we are +# running. Defaults to an empty string if not set. +enquiry-response = + +# Control the auto-update functionality of Ghostty. This is only supported +# on macOS currently, since Linux builds are distributed via package +# managers that are not centrally controlled by Ghostty. +# +# Checking or downloading an update does not send any information to +# the project beyond standard network information mandated by the +# underlying protocols. To put it another way: Ghostty doesn't explicitly +# add any tracking to the update process. The update process works by +# downloading information about the latest version and comparing it +# client-side to the current version. +# +# Valid values are: +# +# * `off` - Disable auto-updates. +# * `check` - Check for updates and notify the user if an update is +# available, but do not automatically download or install the update. +# * `download` - Check for updates, automatically download the update, +# notify the user, but do not automatically install the update. +# +# If unset, we defer to Sparkle's default behavior, which respects the +# preference stored in the standard user defaults (`defaults(1)`). +# +# Changing this value at runtime works after a small delay. +auto-update = + +# The release channel to use for auto-updates. +# +# The default value of this matches the release channel of the currently +# running Ghostty version. If you download a pre-release version of Ghostty +# then this will be set to `tip` and you will receive pre-release updates. +# If you download a stable version of Ghostty then this will be set to +# `stable` and you will receive stable updates. +# +# Valid values are: +# +# * `stable` - Stable, tagged releases such as "1.0.0". +# * `tip` - Pre-release versions generated from each commit to the +# main branch. This is the version that was in use during private +# beta testing by thousands of people. It is generally stable but +# will likely have more bugs than the stable channel. +# +# Changing this configuration requires a full restart of +# Ghostty to take effect. +# +# This only works on macOS since only macOS has an auto-update feature. +auto-update-channel = + diff --git a/ghostty/ghostty-theme b/ghostty/ghostty-theme new file mode 100644 index 0000000..4adedec --- /dev/null +++ b/ghostty/ghostty-theme @@ -0,0 +1,29 @@ +background = #0D1116 +foreground = #ffffff + +cursor-color = #f94dff + +# black +palette = 0=#0D1116 +palette = 8=#e58f2a +# red +palette = 1=#f16c75 +palette = 9=#f16c75 +# green +palette = 2=#37f499 +palette = 10=#37f499 +# yellow +palette = 3=#9ad900 +palette = 11=#9ad900 +# blue +palette = 4=#987afb +palette = 12=#987afb +# purple +palette = 5=#fca6ff +palette = 13=#fca6ff +# aqua +palette = 6=#04d1f9 +palette = 14=#04d1f9 +# white +palette = 7=#ffffff +palette = 15=#ffffff diff --git a/ghostty/reload-config.scpt b/ghostty/reload-config.scpt new file mode 100644 index 0000000..3d574e4 --- /dev/null +++ b/ghostty/reload-config.scpt @@ -0,0 +1,6 @@ +tell application "Ghostty" + activate + tell application "System Events" + keystroke "," using {command down, shift down} -- cmd+shift+, + end tell +end tell diff --git a/ghostty/shaders/animated-gradient-shader.glsl b/ghostty/shaders/animated-gradient-shader.glsl new file mode 100644 index 0000000..01b541c --- /dev/null +++ b/ghostty/shaders/animated-gradient-shader.glsl @@ -0,0 +1,40 @@ +// credits: https://github.com/unkn0wncode +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + + // Create seamless gradient animation + float speed = 0.2; + float gradientFactor = (uv.x + uv.y) / 2.0; + + // Use smoothstep and multiple sin waves for smoother transition + float t = sin(iTime * speed) * 0.5 + 0.5; + gradientFactor = smoothstep(0.0, 1.0, gradientFactor); + + // Create smooth circular animation + float angle = iTime * speed; + vec3 color1 = vec3(0.1, 0.1, 0.5); + vec3 color2 = vec3(0.5, 0.1, 0.1); + vec3 color3 = vec3(0.1, 0.5, 0.1); + + // Smooth interpolation between colors using multiple mix operations + vec3 gradientStartColor = mix( + mix(color1, color2, smoothstep(0.0, 1.0, sin(angle) * 0.5 + 0.5)), + color3, + smoothstep(0.0, 1.0, sin(angle + 2.0) * 0.5 + 0.5) + ); + + vec3 gradientEndColor = mix( + mix(color2, color3, smoothstep(0.0, 1.0, sin(angle + 1.0) * 0.5 + 0.5)), + color1, + smoothstep(0.0, 1.0, sin(angle + 3.0) * 0.5 + 0.5) + ); + + vec3 gradientColor = mix(gradientStartColor, gradientEndColor, gradientFactor); + + vec4 terminalColor = texture(iChannel0, uv); + float mask = 1.0 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb, gradientColor, mask); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/bettercrt.glsl b/ghostty/shaders/bettercrt.glsl new file mode 100644 index 0000000..8f58b89 --- /dev/null +++ b/ghostty/shaders/bettercrt.glsl @@ -0,0 +1,33 @@ +// Original shader collected from: https://www.shadertoy.com/view/WsVSzV +// Licensed under Shadertoy's default since the original creator didn't provide any license. (CC BY NC SA 3.0) +// Slight modifications were made to give a green-ish effect. + +// This shader was modified by April Hall (arithefirst) +// Sourced from https://github.com/m-ahdal/ghostty-shaders/blob/main/retro-terminal.glsl +// Changes made: +// - Removed tint +// - Made the boundaries match ghostty's background color + +float warp = 0.25; // simulate curvature of CRT monitor +float scan = 0.50; // simulate darkness between scanlines + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // squared distance from center + vec2 uv = fragCoord / iResolution.xy; + vec2 dc = abs(0.5 - uv); + dc *= dc; + + // warp the fragment coordinates + uv.x -= 0.5; uv.x *= 1.0 + (dc.y * (0.3 * warp)); uv.x += 0.5; + uv.y -= 0.5; uv.y *= 1.0 + (dc.x * (0.4 * warp)); uv.y += 0.5; + + // determine if we are drawing in a scanline + float apply = abs(sin(fragCoord.y) * 0.25 * scan); + + // sample the texture + vec3 color = texture(iChannel0, uv).rgb; + + // mix the sampled color with the scanline intensity + fragColor = vec4(mix(color, vec3(0.0), apply), 1.0); +} diff --git a/ghostty/shaders/bloom.glsl b/ghostty/shaders/bloom.glsl new file mode 100644 index 0000000..1d20930 --- /dev/null +++ b/ghostty/shaders/bloom.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.2; + } + } + + fragColor = color; +} diff --git a/ghostty/shaders/bloom025.glsl b/ghostty/shaders/bloom025.glsl new file mode 100644 index 0000000..5b6afe9 --- /dev/null +++ b/ghostty/shaders/bloom025.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.025; + } + } + + fragColor = color; +} diff --git a/ghostty/shaders/bloom050.glsl b/ghostty/shaders/bloom050.glsl new file mode 100644 index 0000000..4eb1e22 --- /dev/null +++ b/ghostty/shaders/bloom050.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.050; + } + } + + fragColor = color; +} diff --git a/ghostty/shaders/bloom060.glsl b/ghostty/shaders/bloom060.glsl new file mode 100644 index 0000000..c122fae --- /dev/null +++ b/ghostty/shaders/bloom060.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.060; + } + } + + fragColor = color; +} diff --git a/ghostty/shaders/bloom075.glsl b/ghostty/shaders/bloom075.glsl new file mode 100644 index 0000000..ffb81cb --- /dev/null +++ b/ghostty/shaders/bloom075.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.075; + } + } + + fragColor = color; +} diff --git a/ghostty/shaders/bloom1.glsl b/ghostty/shaders/bloom1.glsl new file mode 100644 index 0000000..86ec7b8 --- /dev/null +++ b/ghostty/shaders/bloom1.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.1; + } + } + + fragColor = color; +} diff --git a/ghostty/shaders/crt.glsl b/ghostty/shaders/crt.glsl new file mode 100644 index 0000000..31d1bec --- /dev/null +++ b/ghostty/shaders/crt.glsl @@ -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 +// +//============================================================== + +// 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); +} \ No newline at end of file diff --git a/ghostty/shaders/cubes.glsl b/ghostty/shaders/cubes.glsl new file mode 100644 index 0000000..2a09505 --- /dev/null +++ b/ghostty/shaders/cubes.glsl @@ -0,0 +1,114 @@ +// credits: https://github.com/rymdlego + +const float speed = 0.2; +const float cube_size = 1.0; +const float cube_brightness = 1.0; +const float cube_rotation_speed = 2.8; +const float camera_rotation_speed = 0.1; + + + +mat3 rotationMatrix(vec3 m,float a) { + m = normalize(m); + float c = cos(a),s=sin(a); + return mat3(c+(1.-c)*m.x*m.x, + (1.-c)*m.x*m.y-s*m.z, + (1.-c)*m.x*m.z+s*m.y, + (1.-c)*m.x*m.y+s*m.z, + c+(1.-c)*m.y*m.y, + (1.-c)*m.y*m.z-s*m.x, + (1.-c)*m.x*m.z-s*m.y, + (1.-c)*m.y*m.z+s*m.x, + c+(1.-c)*m.z*m.z); +} + +float sphere(vec3 pos, float radius) +{ + return length(pos) - radius; +} + +float box(vec3 pos, vec3 size) +{ + float t = iTime; + pos = pos * 0.9 * rotationMatrix(vec3(sin(t/4.0*speed)*10.,cos(t/4.0*speed)*12.,2.7), t*2.4/4.0*speed*cube_rotation_speed); + return length(max(abs(pos) - size, 0.0)); +} + + +float distfunc(vec3 pos) +{ + float t = iTime; + + float size = 0.45 + 0.25*abs(16.0*sin(t*speed/4.0)); + // float size = 2.3 + 1.8*tan((t-5.4)*6.549); + size = cube_size * 0.16 * clamp(size, 2.0, 4.0); + + //pos = pos * rotationMatrix(vec3(0.,-3.,0.7), 3.3 * mod(t/30.0, 4.0)); + vec3 q = mod(pos, 5.0) - 2.5; + float obj1 = box(q, vec3(size)); + return obj1; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + float t = iTime; + vec2 screenPos = -1.0 + 2.0 * fragCoord.xy / iResolution.xy; + screenPos.x *= iResolution.x / iResolution.y; + vec3 cameraOrigin = vec3(t*1.0*speed, 0.0, 0.0); + // vec3 cameraOrigin = vec3(t*1.8*speed, 3.0+t*0.02*speed, 0.0); + vec3 cameraTarget = vec3(t*100., 0.0, 0.0); + cameraTarget = vec3(t*20.0,0.0,0.0) * rotationMatrix(vec3(0.0,0.0,1.0), t*speed*camera_rotation_speed); + + vec3 upDirection = vec3(0.5, 1.0, 0.6); + + vec3 cameraDir = normalize(cameraTarget - cameraOrigin); + vec3 cameraRight = normalize(cross(upDirection, cameraOrigin)); + vec3 cameraUp = cross(cameraDir, cameraRight); + + vec3 rayDir = normalize(cameraRight * screenPos.x + cameraUp * screenPos.y + cameraDir); + + const int MAX_ITER = 64; + const float MAX_DIST = 48.0; + const float EPSILON = 0.001; + + float totalDist = 0.0; + vec3 pos = cameraOrigin; + float dist = EPSILON; + + for (int i = 0; i < MAX_ITER; i++) + { + if (dist < EPSILON || totalDist > MAX_DIST) + break; + dist = distfunc(pos); + totalDist += dist; + pos += dist*rayDir; + } + + vec4 cubes; + + if (dist < EPSILON) + { + // Lighting Code + vec2 eps = vec2(0.0, EPSILON); + vec3 normal = normalize(vec3( + distfunc(pos + eps.yxx) - distfunc(pos - eps.yxx), + distfunc(pos + eps.xyx) - distfunc(pos - eps.xyx), + distfunc(pos + eps.xxy) - distfunc(pos - eps.xxy))); + float diffuse = max(0., dot(-rayDir, normal)); + float specular = pow(diffuse, 32.0); + vec3 color = vec3(diffuse + specular); + vec3 cubeColor = vec3(abs(screenPos),0.5+0.5*sin(t*2.0))*0.8; + cubeColor = mix(cubeColor.rgb, vec3(0.0,0.0,0.0), 1.0); + color += cubeColor; + cubes = vec4(color, 1.0) * vec4(1.0 - (totalDist/MAX_DIST)); + cubes = vec4(cubes.rgb*0.02*cube_brightness, 0.1); + } + else { + cubes = vec4(0.0); + } + + vec2 uv = fragCoord/iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + vec3 blendedColor = terminalColor.rgb + cubes.rgb; + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/cursor_blaze.glsl b/ghostty/shaders/cursor_blaze.glsl new file mode 100644 index 0000000..9cbb57f --- /dev/null +++ b/ghostty/shaders/cursor_blaze.glsl @@ -0,0 +1,117 @@ +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfParallelogram(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3) { + float s = 1.0; + float d = dot(p - v0, p - v0); + + d = seg(p, v0, v3, s, d); + d = seg(p, v1, v0, s, d); + d = seg(p, v2, v1, s, d); + d = seg(p, v3, v2, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float blend(float t) +{ + float sqr = t * t; + return sqr / (2.0 * (sqr - t) + 1.0); +} + +float antialising(float distance) { + return 1. - smoothstep(0., normalize(vec2(2., 2.), 0.).x, distance); +} + +float determineStartVertexFactor(vec2 a, vec2 b) { + // Conditions using step + float condition1 = step(b.x, a.x) * step(a.y, b.y); // a.x < b.x && a.y > b.y + float condition2 = step(a.x, b.x) * step(b.y, a.y); // a.x > b.x && a.y < b.y + + // If neither condition is met, return 1 (else case) + return 1.0 - max(condition1, condition2); +} +vec2 getRectangleCenter(vec4 rectangle) { + return vec2(rectangle.x + (rectangle.z / 2.), rectangle.y - (rectangle.w / 2.)); +} + +const vec4 TRAIL_COLOR = vec4(1.0, 0.725, 0.161, 1.0); +const vec4 TRAIL_COLOR_ACCENT = vec4(1.0, 0., 0., 1.0); +// const vec4 TRAIL_COLOR = vec4(0.482, 0.886, 1.0, 1.0); +// const vec4 TRAIL_COLOR_ACCENT = vec4(0.0, 0.424, 1.0, 1.0); +const vec4 CURRENT_CURSOR_COLOR = TRAIL_COLOR; +const vec4 PREVIOUS_CURSOR_COLOR = TRAIL_COLOR; +const float DURATION = 0.3; + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + //Normalization for fragCoord to a space of -1 to 1; + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + //Normalization for cursor position and size; + //cursor xy has the postion in a space of -1 to 1; + //zw has the width and height + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + //When drawing a parellelogram between cursors for the trail i need to determine where to start at the top-left or top-right vertex of the cursor + float vertexFactor = determineStartVertexFactor(currentCursor.xy, previousCursor.xy); + float invertedVertexFactor = 1.0 - vertexFactor; + + //Set every vertex of my parellogram + vec2 v0 = vec2(currentCursor.x + currentCursor.z * vertexFactor, currentCursor.y - currentCursor.w); + vec2 v1 = vec2(currentCursor.x + currentCursor.z * invertedVertexFactor, currentCursor.y); + vec2 v2 = vec2(previousCursor.x + currentCursor.z * invertedVertexFactor, previousCursor.y); + vec2 v3 = vec2(previousCursor.x + currentCursor.z * vertexFactor, previousCursor.y - previousCursor.w); + + vec4 newColor = vec4(fragColor); + + float progress = blend(clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0)); + + //Distance between cursors determine the total length of the parallelogram; + vec2 centerCC = getRectangleCenter(currentCursor); + vec2 centerCP = getRectangleCenter(previousCursor); + float lineLength = distance(centerCC, centerCP); + float distanceToEnd = distance(vu.xy, centerCC); + float alphaModifier = distanceToEnd / (lineLength * (1.0 - progress)); + + float sdfCursor = getSdfRectangle(vu, currentCursor.xy - (currentCursor.zw * offsetFactor), currentCursor.zw * 0.5); + float sdfTrail = getSdfParallelogram(vu, v0, v1, v2, v3); + + newColor = mix(newColor, TRAIL_COLOR_ACCENT, 1.0 - smoothstep(sdfTrail, -0.01, 0.001)); + newColor = mix(newColor, TRAIL_COLOR, 1.0 - smoothstep(sdfTrail, -0.01, 0.001)); + newColor = mix(newColor, TRAIL_COLOR, antialising(sdfTrail)); + newColor = mix(fragColor, newColor, 1.0 - alphaModifier); + newColor = mix(newColor, TRAIL_COLOR_ACCENT, 1.0 - smoothstep(sdfCursor, -0.000, 0.003 * (1. - progress))); + newColor = mix(newColor, CURRENT_CURSOR_COLOR, 1.0 - smoothstep(sdfCursor, -0.000, 0.003 * (1. - progress))); + fragColor = mix(newColor, fragColor, step(sdfCursor, 0.)); +} diff --git a/ghostty/shaders/cursor_blaze_no_trail.glsl b/ghostty/shaders/cursor_blaze_no_trail.glsl new file mode 100644 index 0000000..87c4e18 --- /dev/null +++ b/ghostty/shaders/cursor_blaze_no_trail.glsl @@ -0,0 +1,162 @@ + +float sdBox(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// //Author: https://iquilezles.org/articles/distfunctions2d/ +float sdTrail(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3) +{ + float d = dot(p - v0, p - v0); + float s = 1.0; + + // Edge from v3 to v0 + { + vec2 e = v3 - v0; + vec2 w = p - v0; + vec2 b = w - e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + d = min(d, dot(b, b)); + + // Compute branchless boolean conditions: + float c0 = step(0.0, p.y - v0.y); // 1 if (p.y >= v0.y) + float c1 = 1.0 - step(0.0, p.y - v3.y); // 1 if (p.y < v3.y) + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); // 1 if (e.x*w.y > e.y*w.x) + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + // If either allCond or noneCond is 1, then flip factor becomes -1. + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + } + + // Edge from v0 to v1 + { + vec2 e = v0 - v1; + vec2 w = p - v1; + vec2 b = w - e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + d = min(d, dot(b, b)); + + float c0 = step(0.0, p.y - v1.y); + float c1 = 1.0 - step(0.0, p.y - v0.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + } + + // Edge from v1 to v2 + { + vec2 e = v1 - v2; + vec2 w = p - v2; + vec2 b = w - e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + d = min(d, dot(b, b)); + + float c0 = step(0.0, p.y - v2.y); + float c1 = 1.0 - step(0.0, p.y - v1.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + } + + // Edge from v2 to v3 + { + vec2 e = v2 - v3; + vec2 w = p - v3; + vec2 b = w - e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + d = min(d, dot(b, b)); + + float c0 = step(0.0, p.y - v3.y); + float c1 = 1.0 - step(0.0, p.y - v2.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + } + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float ParametricBlend(float t) +{ + float sqr = t * t; + return sqr / (2.0 * (sqr - t) + 1.0); +} + +float antialising(float distance) { + return 1. - smoothstep(0., normalize(vec2(2., 2.), 0.).x, distance); +} + +float determineStartVertexFactor(vec2 a, vec2 b) { + // Conditions using step + float condition1 = step(b.x, a.x) * step(a.y, b.y); // a.x < b.x && a.y > b.y + float condition2 = step(a.x, b.x) * step(b.y, a.y); // a.x > b.x && a.y < b.y + + // If neither condition is met, return 1 (else case) + return 1.0 - max(condition1, condition2); +} + +const vec4 TRAIL_COLOR = vec4(0.651, 0.545, 0.980, 1.0); +const vec4 TRAIL_COLOR_ACCENT = vec4(0.957, 0.447, 0.714, 1.0); +// const vec4 TRAIL_COLOR = vec4(0.482, 0.886, 1.0, 1.0); +// const vec4 TRAIL_COLOR_ACCENT = vec4(0.0, 0.424, 1.0, 1.0); +const vec4 CURRENT_CURSOR_COLOR = TRAIL_COLOR; +const vec4 PREVIOUS_CURSOR_COLOR = TRAIL_COLOR; +const float DURATION = 0.3; + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + //Normalization for fragCoord to a space of -1 to 1; + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + //Normalization for cursor position and size; + //cursor xy has the postion in a space of -1 to 1; + //zw has the width and height + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + //When drawing a parellelogram between cursors for the trail i need to determine where to start at the top-left or top-right vertex of the cursor + float vertexFactor = determineStartVertexFactor(currentCursor.xy, previousCursor.xy); + float invertedVertexFactor = 1.0 - vertexFactor; + + //Set every vertex of my parellogram + vec2 v0 = vec2(currentCursor.x + currentCursor.z * vertexFactor, currentCursor.y - currentCursor.w); + vec2 v1 = vec2(currentCursor.x + currentCursor.z * invertedVertexFactor, currentCursor.y); + vec2 v2 = vec2(previousCursor.x + currentCursor.z * invertedVertexFactor, previousCursor.y); + vec2 v3 = vec2(previousCursor.x + currentCursor.z * vertexFactor, previousCursor.y - previousCursor.w); + + vec4 newColor = vec4(fragColor); + + float progress = ParametricBlend(clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0)); + + //Distance between cursors determine the total length of the parallelogram; + float lineLength = distance(currentCursor.xy, previousCursor.xy); + float distanceToEnd = distance(vu.xy, vec2(currentCursor.x + (currentCursor.z / 2.), currentCursor.y - (currentCursor.w / 2.))); + float alphaModifier = distanceToEnd / (lineLength * (1.0 - progress)); + + // float d2 = sdTrail(vu, v0, v1, v2, v3); + // newColor = mix(newColor, TRAIL_COLOR_ACCENT, 1.0 - smoothstep(d2, -0.01, 0.001)); + // newColor = mix(newColor, TRAIL_COLOR, 1.0 - smoothstep(d2, -0.01, 0.001)); + // newColor = mix(newColor, TRAIL_COLOR, antialising(d2)); + + float cCursorDistance = sdBox(vu, currentCursor.xy - (currentCursor.zw * offsetFactor), currentCursor.zw * 0.5); + newColor = mix(newColor, TRAIL_COLOR_ACCENT, 1.0 - smoothstep(cCursorDistance, -0.000, 0.003 * (1. - progress))); + newColor = mix(newColor, CURRENT_CURSOR_COLOR, 1.0 - smoothstep(cCursorDistance, -0.000, 0.003 * (1. - progress))); + + // float pCursorDistance = sdBox(vu, previousCursor.xy - (previousCursor.zw * offsetFactor), previousCursor.zw * 0.5); + // newColor = mix(newColor, PREVIOUS_CURSOR_COLOR, antialising(pCursorDistance)); + + fragColor = mix(fragColor, newColor, 1.); + // fragColor = mix(fragColor, newColor, 1.0 - alphaModifier); +} diff --git a/ghostty/shaders/cursor_smear.glsl b/ghostty/shaders/cursor_smear.glsl new file mode 100644 index 0000000..63119de --- /dev/null +++ b/ghostty/shaders/cursor_smear.glsl @@ -0,0 +1,117 @@ +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching + +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfParallelogram(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3) { + float s = 1.0; + float d = dot(p - v0, p - v0); + + d = seg(p, v0, v3, s, d); + d = seg(p, v1, v0, s, d); + d = seg(p, v2, v1, s, d); + d = seg(p, v3, v2, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float antialising(float distance) { + return 1. - smoothstep(0., normalize(vec2(2., 2.), 0.).x, distance); +} + +float determineStartVertexFactor(vec2 a, vec2 b) { + // Conditions using step + float condition1 = step(b.x, a.x) * step(a.y, b.y); // a.x < b.x && a.y > b.y + float condition2 = step(a.x, b.x) * step(b.y, a.y); // a.x > b.x && a.y < b.y + + // If neither condition is met, return 1 (else case) + return 1.0 - max(condition1, condition2); +} + +vec2 getRectangleCenter(vec4 rectangle) { + return vec2(rectangle.x + (rectangle.z / 2.), rectangle.y - (rectangle.w / 2.)); +} +float ease(float x) { + return pow(1.0 - x, 3.0); +} + +// Use this site to convert from HEX to vec4 +// https://enchanted.games/app/colour-converter/ +// const vec4 TRAIL_COLOR = vec4(1., 1., 0., 1.0); // yellow +const vec4 TRAIL_COLOR = vec4(0.9s76, 0.302, 1.0, 1.0); // cursor +// const vec4 TRAIL_COLOR = vec4(0.914, 0.702, 0.992, 1.0); // light cursor +// const vec4 TRAIL_COLOR = vec4(0.016, 0.82, 0.976, 1.0); // cyan +// const vec4 TRAIL_COLOR = vec4(0.216, 0.957, 0.6, 1.0); // green +const float OPACITY = 0.6; +const float DURATION = 0.10; //IN SECONDS + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + // Normalization for fragCoord to a space of -1 to 1; + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + // Normalization for cursor position and size; + // cursor xy has the postion in a space of -1 to 1; + // zw has the width and height + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + // When drawing a parellelogram between cursors for the trail i need to determine where to start at the top-left or top-right vertex of the cursor + float vertexFactor = determineStartVertexFactor(currentCursor.xy, previousCursor.xy); + float invertedVertexFactor = 1.0 - vertexFactor; + + // Set every vertex of my parellogram + vec2 v0 = vec2(currentCursor.x + currentCursor.z * vertexFactor, currentCursor.y - currentCursor.w); + vec2 v1 = vec2(currentCursor.x + currentCursor.z * invertedVertexFactor, currentCursor.y); + vec2 v2 = vec2(previousCursor.x + currentCursor.z * invertedVertexFactor, previousCursor.y); + vec2 v3 = vec2(previousCursor.x + currentCursor.z * vertexFactor, previousCursor.y - previousCursor.w); + + float sdfCurrentCursor = getSdfRectangle(vu, currentCursor.xy - (currentCursor.zw * offsetFactor), currentCursor.zw * 0.5); + float sdfTrail = getSdfParallelogram(vu, v0, v1, v2, v3); + + float progress = clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0); + float easedProgress = ease(progress); + // Distance between cursors determine the total length of the parallelogram; + vec2 centerCC = getRectangleCenter(currentCursor); + vec2 centerCP = getRectangleCenter(previousCursor); + float lineLength = distance(centerCC, centerCP); + + vec4 newColor = vec4(fragColor); + // Draw trail + newColor = mix(newColor, TRAIL_COLOR, antialising(sdfTrail)); + // Draw current cursor + newColor = mix(newColor, TRAIL_COLOR, antialising(sdfCurrentCursor)); + newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.)); + // newColor = mix(fragColor, newColor, OPACITY); + fragColor = mix(fragColor, newColor, step(sdfCurrentCursor, easedProgress * lineLength)); +} diff --git a/ghostty/shaders/cursor_smear_fade.glsl b/ghostty/shaders/cursor_smear_fade.glsl new file mode 100644 index 0000000..fa8be9d --- /dev/null +++ b/ghostty/shaders/cursor_smear_fade.glsl @@ -0,0 +1,114 @@ +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching + +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfParallelogram(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3) { + float s = 1.0; + float d = dot(p - v0, p - v0); + + d = seg(p, v0, v3, s, d); + d = seg(p, v1, v0, s, d); + d = seg(p, v2, v1, s, d); + d = seg(p, v3, v2, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float antialising(float distance) { + return 1. - smoothstep(0., normalize(vec2(2., 2.), 0.).x, distance); +} + +float determineStartVertexFactor(vec2 a, vec2 b) { + // Conditions using step + float condition1 = step(b.x, a.x) * step(a.y, b.y); // a.x < b.x && a.y > b.y + float condition2 = step(a.x, b.x) * step(b.y, a.y); // a.x > b.x && a.y < b.y + + // If neither condition is met, return 1 (else case) + return 1.0 - max(condition1, condition2); +} + +vec2 getRectangleCenter(vec4 rectangle) { + return vec2(rectangle.x + (rectangle.z / 2.), rectangle.y - (rectangle.w / 2.)); +} +float ease(float x) { + return pow(1.0 - x, 3.0); +} + +const vec4 TRAIL_COLOR = vec4(1., 1., 0., 1.0); +const float DURATION = 0.5; //IN SECONDS + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + // Normalization for fragCoord to a space of -1 to 1; + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + // Normalization for cursor position and size; + // cursor xy has the postion in a space of -1 to 1; + // zw has the width and height + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + // When drawing a parellelogram between cursors for the trail i need to determine where to start at the top-left or top-right vertex of the cursor + float vertexFactor = determineStartVertexFactor(currentCursor.xy, previousCursor.xy); + float invertedVertexFactor = 1.0 - vertexFactor; + + // Set every vertex of my parellogram + vec2 v0 = vec2(currentCursor.x + currentCursor.z * vertexFactor, currentCursor.y - currentCursor.w); + vec2 v1 = vec2(currentCursor.x + currentCursor.z * invertedVertexFactor, currentCursor.y); + vec2 v2 = vec2(previousCursor.x + currentCursor.z * invertedVertexFactor, previousCursor.y); + vec2 v3 = vec2(previousCursor.x + currentCursor.z * vertexFactor, previousCursor.y - previousCursor.w); + + float sdfCurrentCursor = getSdfRectangle(vu, currentCursor.xy - (currentCursor.zw * offsetFactor), currentCursor.zw * 0.5); + float sdfTrail = getSdfParallelogram(vu, v0, v1, v2, v3); + + float progress = clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0); + float easedProgress = ease(progress); + // Distance between cursors determine the total length of the parallelogram; + vec2 centerCC = getRectangleCenter(currentCursor); + vec2 centerCP = getRectangleCenter(previousCursor); + float lineLength = distance(centerCC, centerCP); + + vec4 newColor = vec4(fragColor); + // Compute fade factor based on distance along the trail + float fadeFactor = 1.0 - smoothstep(lineLength, sdfCurrentCursor, easedProgress * lineLength); + + // Apply fading effect to trail color + vec4 fadedTrailColor = TRAIL_COLOR * fadeFactor; + + // Blend trail with fade effect + newColor = mix(newColor, fadedTrailColor, antialising(sdfTrail)); + // Draw current cursor + newColor = mix(newColor, TRAIL_COLOR, antialising(sdfCurrentCursor)); + newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.)); + fragColor = mix(fragColor, newColor, step(sdfCurrentCursor, easedProgress * lineLength)); +} diff --git a/ghostty/shaders/cursor_warp.glsl b/ghostty/shaders/cursor_warp.glsl new file mode 100644 index 0000000..82afade --- /dev/null +++ b/ghostty/shaders/cursor_warp.glsl @@ -0,0 +1,303 @@ +// --- CONFIGURATION --- +vec4 TRAIL_COLOR = vec4(0.957, 0.447, 0.714, 1.0); // can change to eg: vec4(0.2, 0.6, 1.0, 0.5); +const float DURATION = 0.2; // total animation time +const float TRAIL_SIZE = 0.8; // 0.0 = all corners move together. 1.0 = max smear (leading corners jump instantly) +const float THRESHOLD_MIN_DISTANCE = 1.5; // min distance to show trail (units of cursor height) +const float BLUR = 1.0; // blur size in pixels (for antialiasing) +const float TRAIL_THICKNESS = 1.0; // 1.0 = full cursor height, 0.0 = zero height, >1.0 = funky aah +const float TRAIL_THICKNESS_X = 0.9; + +const float FADE_ENABLED = 0.0; // 1.0 to enable fade gradient along the trail, 0.0 to disable +const float FADE_EXPONENT = 5.0; // exponent for fade gradient along the trail + +// --- CONSTANTS for easing functions --- +const float PI = 3.14159265359; +const float C1_BACK = 1.70158; +const float C2_BACK = C1_BACK * 1.525; +const float C3_BACK = C1_BACK + 1.0; +const float C4_ELASTIC = (2.0 * PI) / 3.0; +const float C5_ELASTIC = (2.0 * PI) / 4.5; +const float SPRING_STIFFNESS = 9.0; +const float SPRING_DAMPING = 0.9; + +// --- EASING FUNCTIONS --- + +// // Linear +// float ease(float x) { +// return x; +// } + +// // EaseOutQuad +// float ease(float x) { +// return 1.0 - (1.0 - x) * (1.0 - x); +// } + +// // EaseOutCubic +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 3.0); +// } + +// // EaseOutQuart +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 4.0); +// } + +// // EaseOutQuint +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 5.0); +// } + +// // EaseOutSine +// float ease(float x) { +// return sin((x * PI) / 2.0); +// } + +// // EaseOutExpo +// float ease(float x) { +// return x == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * x); +// } + +// EaseOutCirc +float ease(float x) { + return sqrt(1.0 - pow(x - 1.0, 2.0)); +} + +// // EaseOutBack +// float ease(float x) { +// return 1.0 + C3_BACK * pow(x - 1.0, 3.0) + C1_BACK * pow(x - 1.0, 2.0); +// } + +// // EaseOutElastic +// float ease(float x) { +// return x == 0.0 ? 0.0 +// : x == 1.0 ? 1.0 +// : pow(2.0, -10.0 * x) * sin((x * 10.0 - 0.75) * C4_ELASTIC) + 1.0; +// } + +// // Parametric Spring +// float ease(float x) { +// x = clamp(x, 0.0, 1.0); +// float decay = exp(-SPRING_DAMPING * SPRING_STIFFNESS * x); +// float freq = sqrt(SPRING_STIFFNESS * (1.0 - SPRING_DAMPING * SPRING_DAMPING)); +// float osc = cos(freq * 6.283185 * x) + (SPRING_DAMPING * sqrt(SPRING_STIFFNESS) / freq) * sin(freq * 6.283185 * x); +// return 1.0 - decay * osc; +// } + +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfConvexQuad(in vec2 p, in vec2 v1, in vec2 v2, in vec2 v3, in vec2 v4) { + float s = 1.0; + float d = dot(p - v1, p - v1); + + d = seg(p, v1, v2, s, d); + d = seg(p, v2, v3, s, d); + d = seg(p, v3, v4, s, d); + d = seg(p, v4, v1, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float antialising(float distance, float blurAmount) { + return 1. - smoothstep(0., normalize(vec2(blurAmount, blurAmount), 0.).x, distance); +} + +// Determines animation duration based on a corner's alignment with the move direction(dot product) +// dot_val will be in [-2, 2] +// > 0.5 (1 or 2) = Leading +// > -0.5 (0) = Side +// <= -0.5 (-1 or -2) = Trailing +float getDurationFromDot(float dot_val, float DURATION_LEAD, float DURATION_SIDE, float DURATION_TRAIL) { + float isLead = step(0.5, dot_val); + float isSide = step(-0.5, dot_val) * (1.0 - isLead); + + // Start with trailing duration + float duration = mix(DURATION_TRAIL, DURATION_SIDE, isSide); + // Mix in leading duration + duration = mix(duration, DURATION_LEAD, isLead); + return duration; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // normalization & setup(-1, 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + vec2 halfSizeCC = currentCursor.zw * 0.5; + vec2 centerCP = previousCursor.xy - (previousCursor.zw * offsetFactor); + vec2 halfSizeCP = previousCursor.zw * 0.5; + + float sdfCurrentCursor = getSdfRectangle(vu, centerCC, halfSizeCC); + + float lineLength = distance(centerCC, centerCP); + float minDist = currentCursor.w * THRESHOLD_MIN_DISTANCE; + + vec4 newColor = vec4(fragColor); + + float baseProgress = iTime - iTimeCursorChange; + + if (lineLength > minDist && baseProgress < DURATION - 0.001) { + // defining corners of cursors + + // Y (Height) with TRAIL_THICKNESS + float cc_half_height = currentCursor.w * 0.5; + float cc_center_y = currentCursor.y - cc_half_height; + float cc_new_half_height = cc_half_height * TRAIL_THICKNESS; + float cc_new_top_y = cc_center_y + cc_new_half_height; + float cc_new_bottom_y = cc_center_y - cc_new_half_height; + + // X (Width) with TRAIL_THICKNESS + float cc_half_width = currentCursor.z * 0.5; + float cc_center_x = currentCursor.x + cc_half_width; + float cc_new_half_width = cc_half_width * TRAIL_THICKNESS_X; + float cc_new_left_x = cc_center_x - cc_new_half_width; + float cc_new_right_x = cc_center_x + cc_new_half_width; + + vec2 cc_tl = vec2(cc_new_left_x, cc_new_top_y); + vec2 cc_tr = vec2(cc_new_right_x, cc_new_top_y); + vec2 cc_bl = vec2(cc_new_left_x, cc_new_bottom_y); + vec2 cc_br = vec2(cc_new_right_x, cc_new_bottom_y); + + // same thing for previous cursor + float cp_half_height = previousCursor.w * 0.5; + float cp_center_y = previousCursor.y - cp_half_height; + float cp_new_half_height = cp_half_height * TRAIL_THICKNESS; + float cp_new_top_y = cp_center_y + cp_new_half_height; + float cp_new_bottom_y = cp_center_y - cp_new_half_height; + + float cp_half_width = previousCursor.z * 0.5; + float cp_center_x = previousCursor.x + cp_half_width; + float cp_new_half_width = cp_half_width * TRAIL_THICKNESS_X; + float cp_new_left_x = cp_center_x - cp_new_half_width; + float cp_new_right_x = cp_center_x + cp_new_half_width; + + vec2 cp_tl = vec2(cp_new_left_x, cp_new_top_y); + vec2 cp_tr = vec2(cp_new_right_x, cp_new_top_y); + vec2 cp_bl = vec2(cp_new_left_x, cp_new_bottom_y); + vec2 cp_br = vec2(cp_new_right_x, cp_new_bottom_y); + + // calculating durations for every corner + const float DURATION_TRAIL = DURATION; + const float DURATION_LEAD = DURATION * (1.0 - TRAIL_SIZE); + const float DURATION_SIDE = (DURATION_LEAD + DURATION_TRAIL) / 2.0; + + vec2 moveVec = centerCC - centerCP; + vec2 s = sign(moveVec); + + // dot products for each corner, determining alignment with movement direction + float dot_tl = dot(vec2(-1., 1.), s); + float dot_tr = dot(vec2( 1., 1.), s); + float dot_bl = dot(vec2(-1.,-1.), s); + float dot_br = dot(vec2( 1.,-1.), s); + + // assign durations based on dot products + float dur_tl = getDurationFromDot(dot_tl, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + float dur_tr = getDurationFromDot(dot_tr, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + float dur_bl = getDurationFromDot(dot_bl, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + float dur_br = getDurationFromDot(dot_br, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + + // check direction of horizontal movement + float isMovingRight = step(0.5, s.x); + float isMovingLeft = step(0.5, -s.x); + + // calculate vertical-rail durations + float dot_right_edge = (dot_tr + dot_br) * 0.5; + float dur_right_rail = getDurationFromDot(dot_right_edge, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + + float dot_left_edge = (dot_tl + dot_bl) * 0.5; + float dur_left_rail = getDurationFromDot(dot_left_edge, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + + float final_dur_tl = mix(dur_tl, dur_left_rail, isMovingLeft); + float final_dur_bl = mix(dur_bl, dur_left_rail, isMovingLeft); + + float final_dur_tr = mix(dur_tr, dur_right_rail, isMovingRight); + float final_dur_br = mix(dur_br, dur_right_rail, isMovingRight); + + // calculate progress for each corner based on the duration and time since cursor change + float prog_tl = ease(clamp(baseProgress / final_dur_tl, 0.0, 1.0)); + float prog_tr = ease(clamp(baseProgress / final_dur_tr, 0.0, 1.0)); + float prog_bl = ease(clamp(baseProgress / final_dur_bl, 0.0, 1.0)); + float prog_br = ease(clamp(baseProgress / final_dur_br, 0.0, 1.0)); + + // get the trial corner positions based on progress + vec2 v_tl = mix(cp_tl, cc_tl, prog_tl); + vec2 v_tr = mix(cp_tr, cc_tr, prog_tr); + vec2 v_br = mix(cp_br, cc_br, prog_br); + vec2 v_bl = mix(cp_bl, cc_bl, prog_bl); + + // DRAWING THE TRAIL + float sdfTrail = getSdfConvexQuad(vu, v_tl, v_tr, v_br, v_bl); + + // --- FADE GRADIENT CALCULATION --- + vec2 fragVec = vu - centerCP; + + // project fragment onto movement vector, normalize to [0, 1] + // 0.0 at tail, 1.0 at head + // tiny epsilon to avoid division by zero if moveVec is (0,0) + float fadeProgress = clamp(dot(fragVec, moveVec) / (dot(moveVec, moveVec) + 1e-6), 0.0, 1.0); + + vec4 trail = TRAIL_COLOR; + + float effectiveBlur = BLUR; + if (BLUR < 2.5) { + // no antialising on horizontal/vertical movement, fixes 'pulse' like thing on end cursor + float isDiagonal = abs(s.x) * abs(s.y); // 1.0 if diagonal, 0.0 if H/V + float effectiveBlur = mix(0.0, BLUR, isDiagonal); + } + float shapeAlpha = antialising(sdfTrail, effectiveBlur); // shape mask + + if (FADE_ENABLED > 0.5) { + // apply fade gradient along the trail + // float fadeStart = 0.2; + // float easedProgress = smoothstep(fadeStart, 1.0, fadeProgress); + // easedProgress = pow(2.0, 10.0 * (fadeProgress - 1.0)); + float easedProgress = pow(fadeProgress, FADE_EXPONENT); + trail.a *= easedProgress; + } + + float finalAlpha = trail.a * shapeAlpha; + + // newColor.a to preserve the background alpha. + newColor = mix(newColor, vec4(trail.rgb, newColor.a), finalAlpha); + + // punch hole on the trail, so current cursor is drawn on top + newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.)); + + } + + fragColor = newColor; +} diff --git a/ghostty/shaders/dither.glsl b/ghostty/shaders/dither.glsl new file mode 100644 index 0000000..7bfe740 --- /dev/null +++ b/ghostty/shaders/dither.glsl @@ -0,0 +1,30 @@ +// Simple "dithering" effect +// (c) moni-dz (https://github.com/moni-dz) +// CC BY-NC-SA 4.0 (https://creativecommons.org/licenses/by-nc-sa/4.0/) + +// Packed bayer pattern using bit manipulation +const float bayerPattern[4] = float[4]( + 0x0514, // Encoding 0,8,2,10 + 0xC4E6, // Encoding 12,4,14,6 + 0x3B19, // Encoding 3,11,1,9 + 0xF7D5 // Encoding 15,7,13,5 +); + +float getBayerFromPacked(int x, int y) { + int idx = (x & 3) + ((y & 3) << 2); + return float((int(bayerPattern[y & 3]) >> ((x & 3) << 2)) & 0xF) * (1.0 / 16.0); +} + +#define LEVELS 2.0 // Available color steps per channel +#define INV_LEVELS (1.0 / LEVELS) + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord * (1.0 / iResolution.xy); + vec3 color = texture(iChannel0, uv).rgb; + + float threshold = getBayerFromPacked(int(fragCoord.x), int(fragCoord.y)); + vec3 dithered = floor(color * LEVELS + threshold) * INV_LEVELS; + + fragColor = vec4(dithered, 1.0); +} diff --git a/ghostty/shaders/drunkard.glsl b/ghostty/shaders/drunkard.glsl new file mode 100644 index 0000000..e900d4a --- /dev/null +++ b/ghostty/shaders/drunkard.glsl @@ -0,0 +1,68 @@ +// Drunken stupor effect using fractal Brownian motion and Perlin noise +// (c) moni-dz (https://github.com/moni-dz) +// CC BY-NC-SA 4.0 (https://creativecommons.org/licenses/by-nc-sa/4.0/) + +vec2 hash2(vec2 p) { + uvec2 q = uvec2(floatBitsToUint(p.x), floatBitsToUint(p.y)); + q = (q * uvec2(1597334673U, 3812015801U)) ^ (q.yx * uvec2(2798796415U, 1979697793U)); + return vec2(q) * (1.0/float(0xffffffffU)) * 2.0 - 1.0; +} + +float perlin2d(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + vec2 u = f*f*(3.0-2.0*f); + + return mix(mix(dot(hash2(i + vec2(0.0,0.0)), f - vec2(0.0,0.0)), + dot(hash2(i + vec2(1.0,0.0)), f - vec2(1.0,0.0)), u.x), + mix(dot(hash2(i + vec2(0.0,1.0)), f - vec2(0.0,1.0)), + dot(hash2(i + vec2(1.0,1.0)), f - vec2(1.0,1.0)), u.x), u.y); +} + +#define OCTAVES 10 // How many passes of fractal Brownian motion to perform +#define GAIN 0.5 // How much should each pixel move +#define LACUNARITY 2.0 // How fast should each ripple be per pass + +float fbm(vec2 p) { + float sum = 0.0; + float amp = 0.5; + float freq = 1.0; + + for(int i = 0; i < OCTAVES; i++) { + sum += amp * perlin2d(p * freq); + freq *= LACUNARITY; + amp *= GAIN; + } + + return sum; +} + + +#define NOISE_SCALE 1.0 // How distorted the image you want to be +#define NOISE_INTENSITY 0.05 // How strong the noise effect is +#define ABERRATION true // Chromatic aberration +#define ABERRATION_DELTA 0.1 // How strong the chromatic aberration effect is +#define ANIMATE true +#define SPEED 0.4 // Animation speed + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord/iResolution.xy; + float time = ANIMATE ? iTime * SPEED : 0.0; + + vec2 noisePos = uv * NOISE_SCALE + vec2(time); + float noise = fbm(noisePos) * NOISE_INTENSITY; + + vec3 col; + + if (ABERRATION) { + col.r = texture(iChannel0, uv + vec2(noise * (1.0 + ABERRATION_DELTA))).r; + col.g = texture(iChannel0, uv + vec2(noise)).g; + col.b = texture(iChannel0, uv + vec2(noise * (1.0 - ABERRATION_DELTA))).b; + } else { + vec2 distortedUV = uv + vec2(noise); + col = texture(iChannel0, distortedUV).rgb; + } + + fragColor = vec4(col, 1.0); +} diff --git a/ghostty/shaders/fireworks-rockets.glsl b/ghostty/shaders/fireworks-rockets.glsl new file mode 100644 index 0000000..e2f0b5a --- /dev/null +++ b/ghostty/shaders/fireworks-rockets.glsl @@ -0,0 +1,109 @@ +// This Ghostty shader is a lightly modified port of https://www.shadertoy.com/view/4dBGRw + +#define BLACK_BLEND_THRESHOLD .4 + +//Creates a diagonal red-and-white striped pattern. +vec3 barberpole(vec2 pos, vec2 rocketpos) { + float d = (pos.x - rocketpos.x) + (pos.y - rocketpos.y); + vec3 col = vec3(1.0); + + d = mod(d * 20., 2.0); + if (d > 1.0) { + col = vec3(1.0, 0.0, 0.0); + } + + return col; +} + +vec3 rocket(vec2 pos, vec2 rocketpos) { + vec3 col = vec3(0.0); + float f = 0.; + float absx = abs(rocketpos.x - pos.x); + float absy = abs(rocketpos.y - pos.y); + + // Wooden stick + if (absx < 0.01 && absy < 0.22) { + col = vec3(1.0, 0.5, 0.5); + } + + // Barberpole + if (absx < 0.05 && absy < 0.15) { + col = barberpole(pos, rocketpos); + } + + // Rocket Point + float pointw = (rocketpos.y - pos.y - 0.25) * -0.7; + if ((rocketpos.y - pos.y) > 0.1) { + f = smoothstep(pointw - 0.001, pointw + 0.001, absx); + + col = mix(vec3(1.0, 0.0, 0.0), col, f); + } + + // Shadow + f = -.5 + smoothstep(-0.05, 0.05, (rocketpos.x - pos.x)); + col *= 0.7 + f; + + return col; +} + +float rand(float val, float seed) { + return cos(val * sin(val * seed) * seed); +} + +float distance2(in vec2 a, in vec2 b) { + return dot(a - b, a - b); +} + +mat2 rr = mat2(cos(1.0), -sin(1.0), sin(1.0), cos(1.0)); + +vec3 drawParticles(vec2 pos, vec3 particolor, float time, vec2 cpos, float gravity, float seed, float timelength) { + vec3 col = vec3(0.0); + vec2 pp = vec2(1.0, 0.0); + for (float i = 1.0; i <= 128.0; i++) { + float d = rand(i, seed); + float fade = (i / 128.0) * time; + vec2 particpos = cpos + time * pp * d; + pp = rr * pp; + col = mix(particolor / fade, col, smoothstep(0.0, 0.0001, distance2(particpos, pos))); + } + col *= smoothstep(0.0, 1.0, (timelength - time) / timelength); + + return col; +} +vec3 drawFireworks(float time, vec2 uv, vec3 particolor, float seed) { + float timeoffset = 2.0; + vec3 col = vec3(0.0); + if (time <= 0.) { + return col; + } + if (mod(time, 6.0) > timeoffset) { + col = drawParticles(uv, particolor, mod(time, 6.0) - timeoffset, vec2(rand(ceil(time / 6.0), seed), -0.5), 0.5, ceil(time / 6.0), seed); + } else { + col = rocket(uv * 3., vec2(3. * rand(ceil(time / 6.0), seed), 3. * (-0.5 + (timeoffset - mod(time, 6.0))))); + } + return col; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = 1.0 - 2.0 * fragCoord.xy / iResolution.xy; + uv.x *= iResolution.x / iResolution.y; + vec3 col = vec3(0.1, 0.1, 0.2); + + // Flip the y-axis so that the rocket is drawn from the bottom of the screen + uv.y = -uv.y; + + col += 0.1 * uv.y; + + col += drawFireworks(iTime, uv, vec3(1.0, 0.1, 0.1), 1.); + col += drawFireworks(iTime - 2.0, uv, vec3(0.0, 1.0, 0.5), 2.); + col += drawFireworks(iTime - 4.0, uv, vec3(1.0, 1.0, 0.1), 3.); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, col.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/fireworks.glsl b/ghostty/shaders/fireworks.glsl new file mode 100644 index 0000000..42bc98d --- /dev/null +++ b/ghostty/shaders/fireworks.glsl @@ -0,0 +1,116 @@ +// This Ghostty shader is a port of https://www.shadertoy.com/view/lscGRl + +// "Fireworks" by Martijn Steinrucken aka BigWings - 2015 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +// Email:countfrolic@gmail.com Twitter:@The_ArtOfCode + +#define BLACK_BLEND_THRESHOLD .4 +#define PI 3.141592653589793238 +#define TWOPI 6.283185307179586 +#define S(x,y,z) smoothstep(x,y,z) +#define B(x,y,z,w) S(x-z, x+z, w)*S(y+z, y-z, w) +#define saturate(x) clamp(x,0.,1.) + +#define NUM_EXPLOSIONS 3. +#define NUM_PARTICLES 42. + +// Noise functions by Dave Hoskins +#define MOD3 vec3(.1031,.11369,.13787) +vec3 hash31(float p) { + vec3 p3 = fract(vec3(p) * MOD3); + p3 += dot(p3, p3.yzx + 19.19); + return fract(vec3((p3.x + p3.y) * p3.z, (p3.x + p3.z) * p3.y, (p3.y + p3.z) * p3.x)); +} +float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * MOD3); + p3 += dot(p3, p3.yzx + 19.19); + return fract((p3.x + p3.y) * p3.z); +} + +float circ(vec2 uv, vec2 pos, float size) { + uv -= pos; + + size *= size; + return S(size * 1.1, size, dot(uv, uv)); +} + +float light(vec2 uv, vec2 pos, float size) { + uv -= pos; + + size *= size; + return size / dot(uv, uv); +} + +vec3 explosion(vec2 uv, vec2 p, float seed, float t) { + vec3 col = vec3(0.); + + vec3 en = hash31(seed); + vec3 baseCol = en; + for (float i = 0.; i < NUM_PARTICLES; i++) { + vec3 n = hash31(i) - .5; + + vec2 startP = p - vec2(0., t * t * .1); + vec2 endP = startP + normalize(n.xy) * n.z - vec2(0., t * .2); + + float pt = 1. - pow(t - 1., 2.); + vec2 pos = mix(p, endP, pt); + float size = mix(.01, .005, S(0., .1, pt)); + size *= S(1., .1, pt); + + float sparkle = (sin((pt + n.z) * 21.) * .5 + .5); + sparkle = pow(sparkle, pow(en.x, 3.) * 50.) * mix(0.01, .01, en.y * n.y); + + //size += sparkle*B(.6, 1., .1, t); + size += sparkle * B(en.x, en.y, en.z, t); + + col += baseCol * light(uv, pos, size); + } + + return col; +} + +vec3 Rainbow(vec3 c) { + float t = iTime; + + float avg = (c.r + c.g + c.b) / 3.; + c = avg + (c - avg) * sin(vec3(0., .333, .666) + t); + + c += sin(vec3(.4, .3, .3) * t + vec3(1.1244, 3.43215, 6.435)) * vec3(.4, .1, .5); + + return c; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + uv.x -= .5; + uv.x *= iResolution.x / iResolution.y; + + // Flip the y-axis so that the gravity is downwards + uv.y = -uv.y + 1.; + + float n = hash12(uv + 10.); + float t = iTime * .5; + + vec3 c = vec3(0.); + + for (float i = 0.; i < NUM_EXPLOSIONS; i++) { + float et = t + i * 1234.45235; + float id = floor(et); + et -= id; + + vec2 p = hash31(id).xy; + p.x -= .5; + p.x *= 1.6; + c += explosion(uv, p, id, et); + } + c = Rainbow(c); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, c.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/gears-and-belts.glsl b/ghostty/shaders/gears-and-belts.glsl new file mode 100644 index 0000000..9976b34 --- /dev/null +++ b/ghostty/shaders/gears-and-belts.glsl @@ -0,0 +1,377 @@ +// sligltly modified version of https://www.shadertoy.com/view/DsVSDV +// The only changes are done in the mainImage function +// Ive added comments on what to modify +// works really well with most colorschemes + +#define Rot(a) mat2(cos(a),-sin(a),sin(a),cos(a)) +#define antialiasing(n) n/min(iResolution.y,iResolution.x) +#define S(d,b) smoothstep(antialiasing(3.0),b,d) +#define B(p,s) max(abs(p).x-s.x,abs(p).y-s.y) +#define deg45 .707 +#define R45(p) (( p + vec2(p.y,-p.x) ) *deg45) +#define Tri(p,s) max(R45(p).x,max(R45(p).y,B(p,s))) +#define DF(a,b) length(a) * cos( mod( atan(a.y,a.x)+6.28/(b*8.0), 6.28/((b*8.0)*0.5))+(b-1.)*6.28/(b*8.0) + vec2(0,11) ) + +float random (vec2 p) { + return fract(sin(dot(p.xy, vec2(12.9898,78.233)))* 43758.5453123); +} + +float innerGear(vec2 p, float dir){ + p*=Rot(radians(-iTime*45.+45.)*dir); + vec2 prevP = p; + + //p*=Rot(radians(iTime*45.+20.)); + p = DF(p,7.); + p-=vec2(0.24); + p*=Rot(deg45); + float d = B(p,vec2(0.01,0.06)); + p = prevP; + float d2 = abs(length(p)-0.42)-0.02; + d = min(d,d2); + d2 = abs(length(p)-0.578)-0.02; + d = min(d,d2); + d2 = abs(length(p)-0.499)-0.005; + d = min(d,d2); + + p = DF(p,7.); + p-=vec2(0.43); + p*=Rot(deg45); + d2 = B(p,vec2(0.01,0.04)); + d = min(d,d2); + + return d; +} + +vec3 pattern1(vec2 p, vec3 col, float dir){ + vec2 prevP = p; + float size = 0.499; + float thick = 0.15; + + p+=vec2(size); + float d = abs(length(p)-size)-thick; + d = max(d,innerGear(p,dir)); + col = mix(col,vec3(1.),S(d,0.0)); + + p = prevP; + p-=vec2(size); + d = abs(length(p)-size)-thick; + d = max(d,innerGear(p,dir)); + col = mix(col,vec3(1.),S(d,0.0)); + + return col; +} + +vec3 pattern2(vec2 p, vec3 col, float dir){ + + vec2 prevP = p; + float size = 0.33; + float thick = 0.15; + float thift = 0.0; + float speed = 0.3; + + p-=vec2(size,0.); + float d = B(p,vec2(size,thick)); + + p.x+=thift; + p.x-=iTime*speed*dir; + p.x=mod(p.x,0.08)-0.04; + d = max(d,B(p,vec2(0.011,thick))); + p = prevP; + d = max(-(abs(p.y)-0.1),d); + //d = min(B(p,vec2(1.,0.1)),d); + p.y=abs(p.y)-0.079; + d = min(B(p,vec2(1.,0.02)),d); + + p = prevP; + p-=vec2(0.0,size); + float d2 = B(p,vec2(thick,size)); + + p.y+=thift; + p.y+=iTime*speed*dir; + p.y=mod(p.y,0.08)-0.04; + d2 = max(d2,B(p,vec2(thick,0.011))); + + p = prevP; + d2 = max(-(abs(p.x)-0.1),d2); + d2 = min(B(p,vec2(0.005,1.)),d2); + p.x=abs(p.x)-0.079; + d2 = min(B(p,vec2(0.02,1.)),d2); + + d = min(d,d2); + + p = prevP; + p+=vec2(0.0,size); + d2 = B(p,vec2(thick,size)); + + p.y+=thift; + p.y-=iTime*speed*dir; + p.y=mod(p.y,0.08)-0.04; + d2 = max(d2,B(p,vec2(thick,0.011))); + + p = prevP; + d2 = max(-(abs(p.x)-0.1),d2); + d2 = min(B(p,vec2(0.005,1.)),d2); + p.x=abs(p.x)-0.079; + d2 = min(B(p,vec2(0.02,1.)),d2); + + d = min(d,d2); + + p = prevP; + p+=vec2(size,0.0); + d2 = B(p,vec2(size,thick)); + + p.x+=thift; + p.x+=iTime*speed*dir; + p.x=mod(p.x,0.08)-0.04; + d2 = max(d2,B(p,vec2(0.011,thick))); + d = min(d,d2); + p = prevP; + d = max(-(abs(p.y)-0.1),d); + d = min(B(p,vec2(1.,0.005)),d); + p.y=abs(p.y)-0.079; + d = min(B(p,vec2(1.,0.02)),d); + + p = prevP; + d2 = abs(B(p,vec2(size*0.3)))-0.05; + d = min(d,d2); + + col = mix(col,vec3(1.),S(d,0.0)); + + d = B(p,vec2(0.08)); + col = mix(col,vec3(0.),S(d,0.0)); + + p*=Rot(radians(60.*iTime*dir)); + d = B(p,vec2(0.03)); + col = mix(col,vec3(1.),S(d,0.0)); + + return col; +} + +vec3 drawBelt(vec2 p, vec3 col, float size){ + vec2 prevP = p; + + p*=size; + vec2 id = floor(p); + vec2 gr = fract(p)-0.5; + float dir = mod(id.x+id.y,2.)*2.-1.; + float n = random(id); + + if(n<0.5){ + if(n<0.25){ + gr.x*=-1.; + } + col = pattern1(gr,col,dir); + } else { + if(n>0.75){ + gr.x*=-1.; + } + col = pattern2(gr,col,dir); + } + + return col; +} + +vec3 gear(vec2 p, vec3 col, float dir){ + vec2 prevP = p; + + p*=Rot(radians(iTime*45.+13.)*-dir); + p = DF(p,7.); + p-=vec2(0.23); + p*=Rot(deg45); + float d = B(p,vec2(0.01,0.04)); + p = prevP; + float d2 = abs(length(p)-0.29)-0.02; + d = min(d,d2); + col = mix(col,vec3(1.),S(d,0.0)); + + p*=Rot(radians(iTime*30.-30.)*dir); + p = DF(p,6.); + p-=vec2(0.14); + p*=Rot(radians(45.)); + d = B(p,vec2(0.01,0.03)); + p = prevP; + d2 =abs( length(p)-0.1)-0.02; + p*=Rot(radians(iTime*25.+30.)*-dir); + d2 = max(-(abs(p.x)-0.05),d2); + d = min(d,d2); + col = mix(col,vec3(1.),S(d,0.0)); + + return col; +} + +vec3 item0(vec2 p, vec3 col, float dir){ + vec2 prevP = p; + p.x*=dir; + p*=Rot(radians(iTime*30.+30.)); + float d = abs(length(p)-0.2)-0.05; + col = mix(col,vec3(0.3),S(d,0.0)); + + d = abs(length(p)-0.2)-0.05; + d = max(-p.x,d); + float a = clamp(atan(p.x,p.y)*0.5,0.3,1.); + + col = mix(col,vec3(a),S(d,0.0)); + + return col; +} + + +vec3 item1(vec2 p, vec3 col, float dir){ + p.x*=dir; + vec2 prevP = p; + p*=Rot(radians(iTime*30.+30.)); + float d = abs(length(p)-0.25)-0.04; + d = abs(max((abs(p.y)-0.15),d))-0.005; + float d2 = abs(length(p)-0.25)-0.01; + d2 = max((abs(p.y)-0.12),d2); + d = min(d,d2); + + d2 = abs(length(p)-0.27)-0.01; + d2 = max(-(abs(p.y)-0.22),d2); + d = min(d,d2); + d2 = B(p,vec2(0.01,0.32)); + d2 = max(-(abs(p.y)-0.22),d2); + d = min(d,d2); + + p = prevP; + p*=Rot(radians(iTime*-20.+30.)); + p = DF(p,2.); + p-=vec2(0.105); + p*=Rot(radians(45.)); + d2 = B(p,vec2(0.03,0.01)); + d = min(d,d2); + + p = prevP; + d2 = abs(length(p)-0.09)-0.005; + d2 = max(-(abs(p.x)-0.03),d2); + d2 = max(-(abs(p.y)-0.03),d2); + d = min(d,d2); + + col = mix(col,vec3(0.6),S(d,0.0)); + + return col; +} + +vec3 item2(vec2 p, vec3 col, float dir){ + p.x*=dir; + p*=Rot(radians(iTime*50.-10.)); + vec2 prevP = p; + float d = abs(length(p)-0.15)-0.005; + float d2 = abs(length(p)-0.2)-0.01; + d2 = max((abs(p.y)-0.15),d2); + d = min(d,d2); + + p = DF(p,1.); + p-=vec2(0.13); + p*=Rot(radians(45.)); + d2 = B(p,vec2(0.008,0.1)); + d = min(d,d2); + + p = prevP; + p = DF(p,4.); + p-=vec2(0.18); + p*=Rot(radians(45.)); + d2 = B(p,vec2(0.005,0.02)); + d = min(d,d2); + + col = mix(col,vec3(0.6),S(d,0.0)); + + return col; +} + +float needle(vec2 p){ + p.y-=0.05; + p*=1.5; + vec2 prevP = p; + p.y-=0.3; + p.x*=6.; + float d = Tri(p,vec2(0.3)); + p = prevP; + p.y+=0.1; + p.x*=2.; + p.y*=-1.; + float d2 = Tri(p,vec2(0.1)); + d = min(d,d2); + return d; +} + +vec3 item3(vec2 p, vec3 col, float dir){ + + p*=Rot(radians(sin(iTime*dir)*120.)); + vec2 prevP = p; + + p.y= abs(p.y)-0.05; + float d = needle(p); + p = prevP; + float d2 = abs(length(p)-0.1)-0.003; + d2 = max(-(abs(p.x)-0.05),d2); + d = min(d,d2); + d2 = abs(length(p)-0.2)-0.005; + d2 = max(-(abs(p.x)-0.08),d2); + d = min(d,d2); + + p = DF(p,4.); + p-=vec2(0.18); + d2 = length(p)-0.01; + p = prevP; + d2 = max(-(abs(p.x)-0.03),d2); + d = min(d,d2); + + col = mix(col,vec3(0.6),S(d,0.0)); + + return col; +} + +vec3 drawGearsAndItems(vec2 p, vec3 col, float size){ + vec2 prevP = p; + p*=size; + p+=vec2(0.5); + + vec2 id = floor(p); + vec2 gr = fract(p)-0.5; + + float n = random(id); + float dir = mod(id.x+id.y,2.)*2.-1.; + if(n<0.3){ + col = gear(gr,col,dir); + } else if(n>=0.3 && n<0.5){ + col = item0(gr,col,dir); + } else if(n>=0.5 && n<0.7){ + col = item1(gr,col,dir); + } else if(n>=0.7 && n<0.8) { + col = item2(gr,col,dir); + } else if(n>=0.8){ + col = item3(gr,col,dir); + } + + return col; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 p = (fragCoord-0.5*iResolution.xy)/iResolution.y; + // set speed of downwards motion + p.y+=iTime*0.02; + + float size = 4.; + vec3 col = vec3(0.); + + // Modify the colors to be darker by multiplying with a small factor + vec3 darkFactor = vec3(.5); // This makes everything 50% as bright + + // Get the original colors but make them darker + col = drawBelt(p, col, size) * darkFactor; + col = drawGearsAndItems(p, col, size) * darkFactor; + + // Additional option: you can add a color tint to make it less stark white + vec3 tint = vec3(0.1, 0.12, 0.15); // Slight blue-ish dark tint + col = col * tint; + + vec2 uv = fragCoord/iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + + // Blend with reduced opacity for the shader elements + vec3 blendedColor = terminalColor.rgb + col.rgb * 0.7; // Reduced blend factor + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/glitchy.glsl b/ghostty/shaders/glitchy.glsl new file mode 100644 index 0000000..603e3ec --- /dev/null +++ b/ghostty/shaders/glitchy.glsl @@ -0,0 +1,117 @@ +// modified version of https://www.shadertoy.com/view/wld3WN +// amount of seconds for which the glitch loop occurs +#define DURATION 10. +// percentage of the duration for which the glitch is triggered +#define AMT .1 + +#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. / float(0xffffffffU)) + +// Hash by David_Hoskins +vec3 hash33(vec3 p) +{ + uvec3 q = uvec3(ivec3(p)) * UI3; + q = (q.x ^ q.y ^ q.z)*UI3; + return -1. + 2. * vec3(q) * UIF; +} + +// Gradient noise by iq +float gnoise(vec3 x) +{ + // grid + vec3 p = floor(x); + vec3 w = fract(x); + + // quintic interpolant + vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.); + + // gradients + vec3 ga = hash33(p + vec3(0., 0., 0.)); + vec3 gb = hash33(p + vec3(1., 0., 0.)); + vec3 gc = hash33(p + vec3(0., 1., 0.)); + vec3 gd = hash33(p + vec3(1., 1., 0.)); + vec3 ge = hash33(p + vec3(0., 0., 1.)); + vec3 gf = hash33(p + vec3(1., 0., 1.)); + vec3 gg = hash33(p + vec3(0., 1., 1.)); + vec3 gh = hash33(p + vec3(1., 1., 1.)); + + // projections + float va = dot(ga, w - vec3(0., 0., 0.)); + float vb = dot(gb, w - vec3(1., 0., 0.)); + float vc = dot(gc, w - vec3(0., 1., 0.)); + float vd = dot(gd, w - vec3(1., 1., 0.)); + float ve = dot(ge, w - vec3(0., 0., 1.)); + float vf = dot(gf, w - vec3(1., 0., 1.)); + float vg = dot(gg, w - vec3(0., 1., 1.)); + float vh = dot(gh, w - vec3(1., 1., 1.)); + + // interpolation + float gNoise = 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); + + return 2. * gNoise; +} + +// gradient noise in range [0, 1] +float gnoise01(vec3 x) +{ + return .5 + .5 * gnoise(x); +} + +// warp uvs for the crt effect +vec2 crt(vec2 uv) +{ + float tht = atan(uv.y, uv.x); + float r = length(uv); + // curve without distorting the center + r /= (1. - .1 * r * r); + uv.x = r * cos(tht); + uv.y = r * sin(tht); + return .5 * (uv + 1.); +} + + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord / iResolution.xy; + float t = iTime; + + // smoothed interval for which the glitch gets triggered + float glitchAmount = SS(DURATION * .001, DURATION * AMT, mod(t, DURATION)); + float displayNoise = 0.; + vec3 col = vec3(0.); + vec2 eps = vec2(5. / iResolution.x, 0.); + vec2 st = vec2(0.); + + // analog distortion + float y = uv.y * iResolution.y; + float distortion = gnoise(vec3(0., y * .01, t * 500.)) * (glitchAmount * 4. + .1); + distortion *= gnoise(vec3(0., y * .02, t * 250.)) * (glitchAmount * 2. + .025); + + ++displayNoise; + distortion += smoothstep(.999, 1., sin((uv.y + t * 1.6) * 2.)) * .02; + distortion -= smoothstep(.999, 1., sin((uv.y + t) * 2.)) * .02; + st = uv + vec2(distortion, 0.); + // chromatic aberration + col.r += textureLod(iChannel0, st + eps + distortion, 0.).r; + col.g += textureLod(iChannel0, st, 0.).g; + col.b += textureLod(iChannel0, st - eps - distortion, 0.).b; + + // white noise + scanlines + displayNoise = 0.2 * clamp(displayNoise, 0., 1.); + col += (.15 + .65 * glitchAmount) * (hash33(vec3(fragCoord, mod(float(iFrame), + 1000.))).r) * displayNoise; + col -= (.25 + .75 * glitchAmount) * (sin(4. * t + uv.y * iResolution.y * 1.75)) + * displayNoise; + fragColor = vec4(col, 1.0); +} diff --git a/ghostty/shaders/glow-rgbsplit-twitchy.glsl b/ghostty/shaders/glow-rgbsplit-twitchy.glsl new file mode 100644 index 0000000..9411e4e --- /dev/null +++ b/ghostty/shaders/glow-rgbsplit-twitchy.glsl @@ -0,0 +1,144 @@ +// First it does a "chromatic aberration" by splitting the rgb signals by a product of sin functions +// over time, then it does a glow effect in a perceptual color space +// Based on kalgynirae's Ghostty passable glow shader and NickWest's Chromatic Aberration shader demo +// Passable glow: https://github.com/kalgynirae/dotfiles/blob/main/ghostty/glow.glsl +// "Chromatic Aberration": https://www.shadertoy.com/view/Mds3zn + +// sRGB linear -> nonlinear transform from https://bottosson.github.io/posts/colorwrong/ +float f(float x) { + if (x >= 0.0031308) { + return 1.055 * pow(x, 1.0 / 2.4) - 0.055; + } else { + return 12.92 * x; + } +} + +float f_inv(float x) { + if (x >= 0.04045) { + return pow((x + 0.055) / 1.055, 2.4); + } else { + return x / 12.92; + } +} + +// Oklab <-> linear sRGB conversions from https://bottosson.github.io/posts/oklab/ +vec4 toOklab(vec4 rgb) { + vec3 c = vec3(f_inv(rgb.r), f_inv(rgb.g), f_inv(rgb.b)); + float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b; + float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b; + float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b; + float l_ = pow(l, 1.0 / 3.0); + float m_ = pow(m, 1.0 / 3.0); + float s_ = pow(s, 1.0 / 3.0); + return vec4( + 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_, + 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_, + 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_, + rgb.a + ); +} + +vec4 toRgb(vec4 oklab) { + vec3 c = oklab.rgb; + float l_ = c.r + 0.3963377774 * c.g + 0.2158037573 * c.b; + float m_ = c.r - 0.1055613458 * c.g - 0.0638541728 * c.b; + float s_ = c.r - 0.0894841775 * c.g - 1.2914855480 * c.b; + float l = l_ * l_ * l_; + float m = m_ * m_ * m_; + float s = s_ * s_ * s_; + vec3 linear_srgb = vec3( + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s + ); + return vec4( + clamp(f(linear_srgb.r), 0.0, 1.0), + clamp(f(linear_srgb.g), 0.0, 1.0), + clamp(f(linear_srgb.b), 0.0, 1.0), + oklab.a + ); +} + +// Bloom samples from https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) +}; + +float offsetFunction(float iTime) { + float amount = 1.0; + const float periods[4] = {6.0, 16.0, 19.0, 27.0}; + for (int i = 0; i < 4; i++) { + amount *= 1.0 + 0.5 * sin(iTime*periods[i]); + } + //return amount; + return amount * periods[3]; +} + +const float DIM_CUTOFF = 0.35; +const float BRIGHT_CUTOFF = 0.65; +const float ABBERATION_FACTOR = 0.05; + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + float amount = offsetFunction(iTime); + + vec3 col; + col.r = texture( iChannel0, vec2(uv.x-ABBERATION_FACTOR*amount / iResolution.x, uv.y) ).r; + col.g = texture( iChannel0, uv ).g; + col.b = texture( iChannel0, vec2(uv.x+ABBERATION_FACTOR*amount / iResolution.x, uv.y) ).b; + + vec4 splittedColor = vec4(col, 1.0); + vec4 source = toOklab(splittedColor); + vec4 dest = source; + + if (source.x > DIM_CUTOFF) { + dest.x *= 1.2; + // dest.x = 1.2; + } else { + vec2 step = vec2(1.414) / iResolution.xy; + vec3 glow = vec3(0.0); + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + float weight = s.z; + vec4 c = toOklab(texture(iChannel0, uv + s.xy * step)); + if (c.x > DIM_CUTOFF) { + glow.yz += c.yz * weight * 0.3; + if (c.x <= BRIGHT_CUTOFF) { + glow.x += c.x * weight * 0.05; + } else { + glow.x += c.x * weight * 0.10; + } + } + } + // float lightness_diff = clamp(glow.x - dest.x, 0.0, 1.0); + // dest.x = lightness_diff; + // dest.yz = dest.yz * (1.0 - lightness_diff) + glow.yz * lightness_diff; + dest.xyz += glow.xyz; + } + + fragColor = toRgb(dest); +} diff --git a/ghostty/shaders/gradient-background.glsl b/ghostty/shaders/gradient-background.glsl new file mode 100644 index 0000000..beae0cf --- /dev/null +++ b/ghostty/shaders/gradient-background.glsl @@ -0,0 +1,25 @@ +// credits: https://github.com/unkn0wncode +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // Normalize pixel coordinates (range from 0 to 1) + vec2 uv = fragCoord.xy / iResolution.xy; + + // Create a gradient from bottom right to top left as a function (x + y)/2 + float gradientFactor = (uv.x + uv.y) / 2.0; + + // Define gradient colors (adjust to your preference) + vec3 gradientStartColor = vec3(0.1, 0.1, 0.5); // Start color (e.g., dark blue) + vec3 gradientEndColor = vec3(0.5, 0.1, 0.1); // End color (e.g., dark red) + + vec3 gradientColor = mix(gradientStartColor, gradientEndColor, gradientFactor); + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb, gradientColor, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); +} \ No newline at end of file diff --git a/ghostty/shaders/inside-the-matrix.glsl b/ghostty/shaders/inside-the-matrix.glsl new file mode 100644 index 0000000..6992069 --- /dev/null +++ b/ghostty/shaders/inside-the-matrix.glsl @@ -0,0 +1,413 @@ +/* + Feel free to do anything you want with this code. + This shader uses "runes" code by FabriceNeyret2 (https://www.shadertoy.com/view/4ltyDM) + which is based on "runes" by otaviogood (https://shadertoy.com/view/MsXSRn). + These random runes look good as matrix symbols and have acceptable performance. + + @pkazmier modified this shader to work in Ghostty. +*/ + +const int ITERATIONS = 40; //use less value if you need more performance +const float SPEED = .5; + +const float STRIP_CHARS_MIN = 7.; +const float STRIP_CHARS_MAX = 40.; +const float STRIP_CHAR_HEIGHT = 0.15; +const float STRIP_CHAR_WIDTH = 0.10; +const float ZCELL_SIZE = 1. * (STRIP_CHAR_HEIGHT * STRIP_CHARS_MAX); //the multiplier can't be less than 1. +const float XYCELL_SIZE = 12. * STRIP_CHAR_WIDTH; //the multiplier can't be less than 1. + +const int BLOCK_SIZE = 10; //in cells +const int BLOCK_GAP = 2; //in cells + +const float WALK_SPEED = 0.5 * XYCELL_SIZE; +const float BLOCKS_BEFORE_TURN = 3.; + + +const float PI = 3.14159265359; + + +// ---- random ---- + +float hash(float v) { + return fract(sin(v)*43758.5453123); +} + +float hash(vec2 v) { + return hash(dot(v, vec2(5.3983, 5.4427))); +} + +vec2 hash2(vec2 v) +{ + v = vec2(v * mat2(127.1, 311.7, 269.5, 183.3)); + return fract(sin(v)*43758.5453123); +} + +vec4 hash4(vec2 v) +{ + vec4 p = vec4(v * mat4x2( 127.1, 311.7, + 269.5, 183.3, + 113.5, 271.9, + 246.1, 124.6 )); + return fract(sin(p)*43758.5453123); +} + +vec4 hash4(vec3 v) +{ + vec4 p = vec4(v * mat4x3( 127.1, 311.7, 74.7, + 269.5, 183.3, 246.1, + 113.5, 271.9, 124.6, + 271.9, 269.5, 311.7 ) ); + return fract(sin(p)*43758.5453123); +} + + +// ---- symbols ---- +// Slightly modified version of "runes" by FabriceNeyret2 - https://www.shadertoy.com/view/4ltyDM +// Which is based on "runes" by otaviogood - https://shadertoy.com/view/MsXSRn + +float rune_line(vec2 p, vec2 a, vec2 b) { // from https://www.shadertoy.com/view/4dcfW8 + p -= a, b -= a; + float h = clamp(dot(p, b) / dot(b, b), 0., 1.); // proj coord on line + return length(p - b * h); // dist to segment +} + +float rune(vec2 U, vec2 seed, float highlight) +{ + float d = 1e5; + for (int i = 0; i < 4; i++) // number of strokes + { + vec4 pos = hash4(seed); + seed += 1.; + + // each rune touches the edge of its box on all 4 sides + if (i == 0) pos.y = .0; + if (i == 1) pos.x = .999; + if (i == 2) pos.x = .0; + if (i == 3) pos.y = .999; + // snap the random line endpoints to a grid 2x3 + vec4 snaps = vec4(2, 3, 2, 3); + pos = ( floor(pos * snaps) + .5) / snaps; + + if (pos.xy != pos.zw) //filter out single points (when start and end are the same) + d = min(d, rune_line(U, pos.xy, pos.zw + .001) ); // closest line + } + return smoothstep(0.1, 0., d) + highlight*smoothstep(0.4, 0., d); +} + +float random_char(vec2 outer, vec2 inner, float highlight) { + vec2 seed = vec2(dot(outer, vec2(269.5, 183.3)), dot(outer, vec2(113.5, 271.9))); + return rune(inner, seed, highlight); +} + + +// ---- digital rain ---- + +// xy - horizontal, z - vertical +vec3 rain(vec3 ro3, vec3 rd3, float time) { + vec4 result = vec4(0.); + + // normalized 2d projection + vec2 ro2 = vec2(ro3); + vec2 rd2 = normalize(vec2(rd3)); + + // we use formulas `ro3 + rd3 * t3` and `ro2 + rd2 * t2`, `t3_to_t2` is a multiplier to convert t3 to t2 + bool prefer_dx = abs(rd2.x) > abs(rd2.y); + float t3_to_t2 = prefer_dx ? rd3.x / rd2.x : rd3.y / rd2.y; + + // at first, horizontal space (xy) is divided into cells (which are columns in 3D) + // then each xy-cell is divided into vertical cells (along z) - each of these cells contains one raindrop + + ivec3 cell_side = ivec3(step(0., rd3)); //for positive rd.x use cell side with higher x (1) as the next side, for negative - with lower x (0), the same for y and z + ivec3 cell_shift = ivec3(sign(rd3)); //shift to move to the next cell + + // move through xy-cells in the ray direction + float t2 = 0.; // the ray formula is: ro2 + rd2 * t2, where t2 is positive as the ray has a direction. + ivec2 next_cell = ivec2(floor(ro2/XYCELL_SIZE)); //first cell index where ray origin is located + for (int i=0; i= t2s && tmin <= t2) { + float u = s.x * rd2.y - s.y * rd2.x; //horizontal coord in the matrix strip + if (abs(u) < target_rad) { + u = (u/target_rad + 1.) / 2.; + float z = ro3.z + rd3.z * tmin/t3_to_t2; + float v = (z - target_z) / target_length; //vertical coord in the matrix strip + if (v >= 0.0 && v < 1.0) { + float c = floor(v * chars_count); //symbol index relative to the start of the strip, with addition of char_z_shift it becomes an index relative to the whole cell + float q = fract(v * chars_count); + vec2 char_hash = hash2(vec2(c+char_z_shift, cell_hash2.x)); + if (char_hash.x >= 0.1 || c == 0.) { //10% of missed symbols + float time_factor = floor(c == 0. ? time*5.0 : //first symbol is changed fast + time*(1.0*cell_hash2.z + //strips are changed sometime with different speed + cell_hash2.w*cell_hash2.w*4.*pow(char_hash.y, 4.))); //some symbols in some strips are changed relatively often + float a = random_char(vec2(char_hash.x, time_factor), vec2(u,q), max(1., 3. - c/2.)*0.2); //alpha + a *= clamp((chars_count - 0.5 - c) / 2., 0., 1.); //tail fade + if (a > 0.) { + float attenuation = 1. + pow(0.06*tmin/t3_to_t2, 2.); + vec3 col = (c == 0. ? vec3(0.67, 1.0, 0.82) : vec3(0.25, 0.80, 0.40)) / attenuation; + float a1 = result.a; + result.a = a1 + (1. - a1) * a; + result.xyz = (result.xyz * a1 + col * (1. - a1) * a) / result.a; + if (result.a > 0.98) return result.xyz; + } + } + } + } + } + // not found in this cell - go to next vertical cell + zcell += cell_shift.z; + } + // go to next horizontal cell + } + + return result.xyz * result.a; +} + + +// ---- main, camera ---- + +vec2 rotate(vec2 v, float a) { + float s = sin(a); + float c = cos(a); + mat2 m = mat2(c, -s, s, c); + return m * v; +} + +vec3 rotateX(vec3 v, float a) { + float s = sin(a); + float c = cos(a); + return mat3(1.,0.,0.,0.,c,-s,0.,s,c) * v; +} + +vec3 rotateY(vec3 v, float a) { + float s = sin(a); + float c = cos(a); + return mat3(c,0.,-s,0.,1.,0.,s,0.,c) * v; +} + +vec3 rotateZ(vec3 v, float a) { + float s = sin(a); + float c = cos(a); + return mat3(c,-s,0.,s,c,0.,0.,0.,1.) * v; +} + +float smoothstep1(float x) { + return smoothstep(0., 1., x); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + if (STRIP_CHAR_WIDTH > XYCELL_SIZE || STRIP_CHAR_HEIGHT * STRIP_CHARS_MAX > ZCELL_SIZE) { + // error + fragColor = vec4(1., 0., 0., 1.); + return; + } + + vec2 uv = fragCoord.xy / iResolution.xy; + + float time = iTime * SPEED; + + const float turn_rad = 0.25 / BLOCKS_BEFORE_TURN; //0 .. 0.5 + const float turn_abs_time = (PI/2.*turn_rad) * 1.5; //multiplier different than 1 means a slow down on turns + const float turn_time = turn_abs_time / (1. - 2.*turn_rad + turn_abs_time); //0..1, but should be <= 0.5 + + float level1_size = float(BLOCK_SIZE) * BLOCKS_BEFORE_TURN * XYCELL_SIZE; + float level2_size = 4. * level1_size; + float gap_size = float(BLOCK_GAP) * XYCELL_SIZE; + + vec3 ro = vec3(gap_size/2., gap_size/2., 0.); + vec3 rd = vec3(uv.x, 2.0, uv.y); + + float tq = fract(time / (level2_size*4.) * WALK_SPEED); //the whole cycle time counter + float t8 = fract(tq*4.); //time counter while walking on one of the four big sides + float t1 = fract(t8*8.); //time counter while walking on one of the eight sides of the big side + + vec2 prev; + vec2 dir; + if (tq < 0.25) { + prev = vec2(0.,0.); + dir = vec2(0.,1.); + } else if (tq < 0.5) { + prev = vec2(0.,1.); + dir = vec2(1.,0.); + } else if (tq < 0.75) { + prev = vec2(1.,1.); + dir = vec2(0.,-1.); + } else { + prev = vec2(1.,0.); + dir = vec2(-1.,0.); + } + float angle = floor(tq * 4.); //0..4 wich means 0..2*PI + + prev *= 4.; + + const float first_turn_look_angle = 0.4; + const float second_turn_drift_angle = 0.5; + const float fifth_turn_drift_angle = 0.25; + + vec2 turn; + float turn_sign = 0.; + vec2 dirL = rotate(dir, -PI/2.); + vec2 dirR = -dirL; + float up_down = 0.; + float rotate_on_turns = 1.; + float roll_on_turns = 1.; + float add_angel = 0.; + if (t8 < 0.125) { + turn = dirL; + //dir = dir; + turn_sign = -1.; + angle -= first_turn_look_angle * (max(0., t1 - (1. - turn_time*2.)) / turn_time - max(0., t1 - (1. - turn_time)) / turn_time * 2.5); + roll_on_turns = 0.; + } else if (t8 < 0.250) { + prev += dir; + turn = dir; + dir = dirL; + angle -= 1.; + turn_sign = 1.; + add_angel += first_turn_look_angle*0.5 + (-first_turn_look_angle*0.5+1.0+second_turn_drift_angle)*t1; + rotate_on_turns = 0.; + roll_on_turns = 0.; + } else if (t8 < 0.375) { + prev += dir + dirL; + turn = dirR; + //dir = dir; + turn_sign = 1.; + add_angel += second_turn_drift_angle*sqrt(1.-t1); + //roll_on_turns = 0.; + } else if (t8 < 0.5) { + prev += dir + dir + dirL; + turn = dirR; + dir = dirR; + angle += 1.; + turn_sign = 0.; + up_down = sin(t1*PI) * 0.37; + } else if (t8 < 0.625) { + prev += dir + dir; + turn = dir; + dir = dirR; + angle += 1.; + turn_sign = -1.; + up_down = sin(-min(1., t1/(1.-turn_time))*PI) * 0.37; + } else if (t8 < 0.750) { + prev += dir + dir + dirR; + turn = dirL; + //dir = dir; + turn_sign = -1.; + add_angel -= (fifth_turn_drift_angle + 1.) * smoothstep1(t1); + rotate_on_turns = 0.; + roll_on_turns = 0.; + } else if (t8 < 0.875) { + prev += dir + dir + dir + dirR; + turn = dir; + dir = dirL; + angle -= 1.; + turn_sign = 1.; + add_angel -= fifth_turn_drift_angle - smoothstep1(t1) * (fifth_turn_drift_angle * 2. + 1.); + rotate_on_turns = 0.; + roll_on_turns = 0.; + } else { + prev += dir + dir + dir; + turn = dirR; + //dir = dir; + turn_sign = 1.; + angle += fifth_turn_drift_angle * (1.5*min(1., (1.-t1)/turn_time) - 0.5*smoothstep1(1. - min(1.,t1/(1.-turn_time)))); + } + + if (iMouse.x > 10. || iMouse.y > 10.) { + vec2 mouse = iMouse.xy / iResolution.xy * 2. - 1.; + up_down = -0.7 * mouse.y; + angle += mouse.x; + rotate_on_turns = 1.; + roll_on_turns = 0.; + } else { + angle += add_angel; + } + + rd = rotateX(rd, up_down); + + vec2 p; + if (turn_sign == 0.) { + // move forward + p = prev + dir * (turn_rad + 1. * t1); + } + else if (t1 > (1. - turn_time)) { + // turn + float tr = (t1 - (1. - turn_time)) / turn_time; + vec2 c = prev + dir * (1. - turn_rad) + turn * turn_rad; + p = c + turn_rad * rotate(dir, (tr - 1.) * turn_sign * PI/2.); + angle += tr * turn_sign * rotate_on_turns; + rd = rotateY(rd, sin(tr*turn_sign*PI) * 0.2 * roll_on_turns); //roll + } else { + // move forward + t1 /= (1. - turn_time); + p = prev + dir * (turn_rad + (1. - turn_rad*2.) * t1); + } + + rd = rotateZ(rd, angle * PI/2.); + + ro.xy += level1_size * p; + + ro += rd * 0.2; + rd = normalize(rd); + + // vec3 col = rain(ro, rd, time); + vec3 col = rain(ro, rd, time) * 0.25; + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Combine the matrix effect with the terminal color + // vec3 blendedColor = terminalColor.rgb + col; + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1.2 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb * 1.2, col, mask); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/just-snow.glsl b/ghostty/shaders/just-snow.glsl new file mode 100644 index 0000000..c72b7fd --- /dev/null +++ b/ghostty/shaders/just-snow.glsl @@ -0,0 +1,52 @@ +// Copyright (c) 2013 Andrew Baldwin (twitter: baldand, www: http://thndl.com) +// License = Attribution-NonCommercial-ShareAlike (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US) + +// "Just snow" +// Simple (but not cheap) snow made from multiple parallax layers with randomly positioned +// flakes and directions. Also includes a DoF effect. Pan around with mouse. + +#define LIGHT_SNOW // Comment this out for a blizzard + +#ifdef LIGHT_SNOW + #define LAYERS 50 + #define DEPTH .5 + #define WIDTH .3 + #define SPEED .6 +#else // BLIZZARD + #define LAYERS 200 + #define DEPTH .1 + #define WIDTH .8 + #define SPEED 1.5 +#endif + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + const mat3 p = mat3(13.323122,23.5112,21.71123,21.1212,28.7312,11.9312,21.8112,14.7212,61.3934); + vec2 uv = fragCoord.xy / iResolution.xy; + + vec3 acc = vec3(0.0); + float dof = 5.0 * sin(iTime * 0.1); + for (int i = 0; i < LAYERS; i++) { + float fi = float(i); + vec2 q =-uv*(1.0 + fi * DEPTH); + q += vec2(q.y * (WIDTH * mod(fi * 7.238917, 1.0) - WIDTH * 0.5), -SPEED * iTime / (1.0 + fi * DEPTH * 0.03)); + vec3 n = vec3(floor(q), 31.189 + fi); + vec3 m = floor(n) * 0.00001 + fract(n); + vec3 mp = (31415.9 + m) / fract(p * m); + vec3 r = fract(mp); + vec2 s = abs(mod(q, 1.0) - 0.5 + 0.9 * r.xy - 0.45); + s += 0.01 * abs(2.0 * fract(10.0 * q.yx) - 1.0); + float d = 0.6 * max(s.x - s.y, s.x + s.y) + max(s.x, s.y) - 0.01; + float edge = 0.005 + 0.05 * min(0.5 * abs(fi - 5.0 - dof), 1.0); + acc += vec3(smoothstep(edge, -edge, d) * (r.x / (1.0 + 0.02 * fi * DEPTH))); + } + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Combine the snow effect with the terminal color + vec3 blendedColor = terminalColor.rgb + acc; + + // Use the terminal's original alpha + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/matrix-hallway.glsl b/ghostty/shaders/matrix-hallway.glsl new file mode 100644 index 0000000..2bbee86 --- /dev/null +++ b/ghostty/shaders/matrix-hallway.glsl @@ -0,0 +1,40 @@ +// based on the following Shader Toy entry +// +// [SH17A] Matrix rain. Created by Reinder Nijhoff 2017 +// Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +// @reindernijhoff +// +// https://www.shadertoy.com/view/ldjBW1 +// + +#define SPEED_MULTIPLIER 1. +#define GREEN_ALPHA .33 + +#define BLACK_BLEND_THRESHOLD .4 + +#define R fract(1e2 * sin(p.x * 8. + p.y)) + +void mainImage(out vec4 fragColor, vec2 fragCoord) { + vec3 v = vec3(fragCoord, 1) / iResolution - .5; + // vec3 s = .5 / abs(v); + // scale? + vec3 s = .9 / abs(v); + s.z = min(s.y, s.x); + vec3 i = ceil( 8e2 * s.z * ( s.y < s.x ? v.xzz : v.zyz ) ) * .1; + vec3 j = fract(i); + i -= j; + vec3 p = vec3(9, int(iTime * SPEED_MULTIPLIER * (9. + 8. * sin(i).x)), 0) + i; + vec3 col = fragColor.rgb; + col.g = R / s.z; + p *= j; + col *= (R >.5 && j.x < .6 && j.y < .8) ? GREEN_ALPHA : 0.; + + // Sample the terminal screen texture including alpha channel + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.2, col, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/negative.glsl b/ghostty/shaders/negative.glsl new file mode 100644 index 0000000..48101f6 --- /dev/null +++ b/ghostty/shaders/negative.glsl @@ -0,0 +1,8 @@ + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord/iResolution.xy; + vec4 color = texture(iChannel0, uv); + fragColor = vec4(1.0 - color.x, 1.0 - color.y, 1.0 - color.z, color.w); +} + diff --git a/ghostty/shaders/retro-terminal.glsl b/ghostty/shaders/retro-terminal.glsl new file mode 100644 index 0000000..c5f315a --- /dev/null +++ b/ghostty/shaders/retro-terminal.glsl @@ -0,0 +1,34 @@ +// Original shader collected from: https://www.shadertoy.com/view/WsVSzV +// Licensed under Shadertoy's default since the original creator didn't provide any license. (CC BY NC SA 3.0) +// Slight modifications were made to give a green-ish effect. + +float warp = 0.25; // simulate curvature of CRT monitor +float scan = 0.50; // simulate darkness between scanlines + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // squared distance from center + vec2 uv = fragCoord / iResolution.xy; + vec2 dc = abs(0.5 - uv); + dc *= dc; + + // warp the fragment coordinates + uv.x -= 0.5; uv.x *= 1.0 + (dc.y * (0.3 * warp)); uv.x += 0.5; + uv.y -= 0.5; uv.y *= 1.0 + (dc.x * (0.4 * warp)); uv.y += 0.5; + + // sample inside boundaries, otherwise set to black + if (uv.y > 1.0 || uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0) + fragColor = vec4(0.0, 0.0, 0.0, 1.0); + else + { + // determine if we are drawing in a scanline + float apply = abs(sin(fragCoord.y) * 0.5 * scan); + + // sample the texture and apply a teal tint + vec3 color = texture(iChannel0, uv).rgb; + vec3 tealTint = vec3(0.0, 0.8, 0.6); // teal color (slightly more green than blue) + + // mix the sampled color with the teal tint based on scanline intensity + fragColor = vec4(mix(color * tealTint, vec3(0.0), apply), 1.0); + } +} diff --git a/ghostty/shaders/ripple_cursor.glsl b/ghostty/shaders/ripple_cursor.glsl new file mode 100644 index 0000000..30a14cf --- /dev/null +++ b/ghostty/shaders/ripple_cursor.glsl @@ -0,0 +1,132 @@ +// CONFIGURATION +const float DURATION = 0.15; // How long the ripple animates (seconds) +const float MAX_RADIUS = 0.05; // Max radius in normalized coords (0.5 = 1/4 screen height) +const float RING_THICKNESS = 0.02; // Ring width in normalized coords +const float CURSOR_WIDTH_CHANGE_THRESHOLD = 0.5; // Triggers ripple if cursor width changes by this fraction +vec4 COLOR = iCurrentCursor; // change to iCurrentCursorColor for your cursor's color +const float BLUR = 3.0; // Blur level in pixels +const float ANIMATION_START_OFFSET = 0.0; // Start the ripple slightly progressed (0.0 - 1.0) + + +// Easing functions +float easeOutQuad(float t) { + return 1.0 - (1.0 - t) * (1.0 - t); +} +float easeInOutQuad(float t) { + return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0; +} +float easeOutCubic(float t) { + return 1.0 - pow(1.0 - t, 3.0); +} +float easeOutQuart(float t) { + return 1.0 - pow(1.0 - t, 4.0); +} +float easeOutQuint(float t) { + return 1.0 - pow(1.0 - t, 5.0); +} +float easeOutExpo(float t) { + return t == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * t); +} +float easeOutCirc(float t) { + return sqrt(1.0 - pow(t - 1.0, 2.0)); +} +float easeOutSine(float t) { + return sin((t * 3.1415916) / 2.0); +} +float easeOutElastic(float t) { + const float c4 = (2.0 * 3.1415916) / 3.0; + return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0; +} +float easeOutBounce(float t) { + const float n1 = 7.5625; + const float d1 = 2.75; + if (t < 1.0 / d1) { + return n1 * t * t; + } else if (t < 2.0 / d1) { + return n1 * (t -= 1.5 / d1) * t + 0.75; + } else if (t < 2.5 / d1) { + return n1 * (t -= 2.25 / d1) * t + 0.9375; + } else { + return n1 * (t -= 2.625 / d1) * t + 0.984375; + } +} +float easeOutBack(float t) { + const float c1 = 1.70158; + const float c3 = c1 + 1.0; + return 1.0 + c3 * pow(t - 1.0, 3.0) + c1 * pow(t - 1.0, 2.0); +} + +// Pulse fade functions +float easeOutPulse(float t) { + return t * (2.0 - t); +} +float exponentialDecayPulse(float t) { + return exp(-3.0 * t) * sin(t * 3.1415916); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // Normalization & setup (-1 to 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + + float cellWidth = max(currentCursor.z, previousCursor.z); // width of the 'block' cursor + + // check for significant width change + float widthChange = abs(currentCursor.z - previousCursor.z); + float widthThresholdNorm = cellWidth * CURSOR_WIDTH_CHANGE_THRESHOLD; + float isModeChange = step(widthThresholdNorm, widthChange); + + + // ANIMATION + float rippleProgress = (iTime - iTimeCursorChange) / DURATION + ANIMATION_START_OFFSET; + // don't clamp yet; we need to know if it's > 1.0 (finished) + float isAnimating = 1.0 - step(1.0, rippleProgress); // progress < 1.0 ? 1.0: 0.0 + + if (isModeChange > 0.0 && isAnimating > 0.0) { + // Apply easing to progress + // float easedProgress = rippleProgress; + // float easedProgress = easeOutQuad(rippleProgress); + // float easedProgress = easeInOutQuad(rippleProgress); + // float easedProgress = easeOutCubic(rippleProgress); + // float easedProgress = easeOutQuart(rippleProgress); + // float easedProgress = easeOutQuint(rippleProgress); + // float easedProgress = easeOutExpo(rippleProgress); + float easedProgress = easeOutCirc(rippleProgress); + // float easedProgress = easeOutSine(rippleProgress); + // float easedProgress = easeOutBack(rippleProgress); + + // RIPPLE CALCULATION + float rippleRadius = easedProgress * MAX_RADIUS; + + // float fade = 1.0; // no fade + // float fade = 1.0 - easedProgress; // linear fade + float fade = 1.0 - easeOutPulse(rippleProgress); + // float fade = 1.0 - exponentialDecayPulse(rippleProgress); + + // Calculate distance from frag to cursor center + float dist = distance(vu, centerCC); + + float sdfRing = abs(dist - rippleRadius) - RING_THICKNESS * 0.5; + + // Antialias (1-pixel width in normalized coords) + float antiAliasSize = normalize(vec2(BLUR, BLUR), 0.0).x; + float ripple = (1.0 - smoothstep(-antiAliasSize, antiAliasSize, sdfRing)) * fade; + + // Apply ripple effect + fragColor = mix(fragColor, COLOR, ripple * COLOR.a); + } + // else: do nothing, keep original fragColor +} diff --git a/ghostty/shaders/smoke-and-ghost.glsl b/ghostty/shaders/smoke-and-ghost.glsl new file mode 100644 index 0000000..a11f8dc --- /dev/null +++ b/ghostty/shaders/smoke-and-ghost.glsl @@ -0,0 +1,193 @@ +// Settings for detection +#define TARGET_COLOR vec3(0.0, 0.0, 0.0) // RGB target pixels to transform +#define REPLACE_COLOR vec3(0.0, 0.0, 0.0) // Color to replace target pixels +#define COLOR_TOLERANCE 0.001 // Color matching tolerance + +// Smoke effect settings +#define SMOKE_COLOR vec3(1., 1., 1.0) // Base color of smoke +#define SMOKE_RADIUS 0.011 // How far the smoke spreads +#define SMOKE_SPEED 0.5 // Speed of smoke movement +#define SMOKE_SCALE 25.0 // Scale of smoke detail +#define SMOKE_INTENSITY 0.2 // Intensity of the smoke effect +#define SMOKE_RISE_HEIGHT 0.14 // How high the smoke rises +#define ALPHA_MAX 0.5 // Maximum opacity for smoke +#define VERTICAL_BIAS 1.0 + +// Ghost face settings +#define FACE_COUNT 1 // Number of ghost faces +#define FACE_SCALE vec2(0.03, 0.05) // Size of faces, can be wider/elongated +#define FACE_DURATION 1.2 // How long faces last, can be wider/elongated +#define FACE_TRANSITION 1.5 // Face fade in/out duration +#define FACE_COLOR vec3(0.0, 0.0, 0.0) +#define GHOST_BG_COLOR vec3(1.0, 1.0, 1.0) +#define GHOST_BG_SCALE vec2(0.03, 0.06) + +float random(vec2 st) { + return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); +} + +float random1(float n) { + return fract(sin(n) * 43758.5453123); +} + +vec2 random2(float n) { + return vec2( + random1(n), + random1(n + 1234.5678) + ); +} + +float noise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + float a = random(i); + float b = random(i + vec2(1.0, 0.0)); + float c = random(i + vec2(0.0, 1.0)); + float d = random(i + vec2(1.0, 1.0)); + + vec2 u = f * f * (3.0 - 2.0 * f); + return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; +} + +// Modified elongated ellipse for more cartoon-like shapes +float cartoonEllipse(vec2 uv, vec2 center, vec2 scale) { + vec2 d = (uv - center) / scale; + float len = length(d); + // Add cartoon-like falloff + return smoothstep(1.0, 0.8, len); +} + +// Function to create ghost background shape +float ghostBackground(vec2 uv, vec2 center) { + vec2 d = (uv - center) / GHOST_BG_SCALE; + float baseShape = length(d * vec2(1.0, 0.8)); // Slightly oval + + // Add wavy bottom + float wave = sin(d.x * 6.28 + iTime) * 0.2; + float bottomWave = smoothstep(0.0, -0.5, d.y + wave); + + return smoothstep(1.0, 0.8, baseShape) + bottomWave; +} + +float ghostFace(vec2 uv, vec2 center, float time, float seed) { + vec2 faceUV = (uv - center) / FACE_SCALE; + + float eyeSize = 0.25 + random1(seed) * 0.05; + float eyeSpacing = 0.35; + vec2 leftEyePos = vec2(-eyeSpacing, 0.2); + vec2 rightEyePos = vec2(eyeSpacing, 0.2); + + float leftEye = cartoonEllipse(faceUV, leftEyePos, vec2(eyeSize)); + float rightEye = cartoonEllipse(faceUV, rightEyePos, vec2(eyeSize)); + + // Add simple eye highlights + float leftHighlight = cartoonEllipse(faceUV, leftEyePos + vec2(0.1, 0.1), vec2(eyeSize * 0.3)); + float rightHighlight = cartoonEllipse(faceUV, rightEyePos + vec2(0.1, 0.1), vec2(eyeSize * 0.3)); + + vec2 mouthUV = faceUV - vec2(0.0, -0.9); + float mouthWidth = 0.5 + random1(seed + 3.0) * 0.1; + float mouthHeight = 0.8 + random1(seed + 7.0) * 0.1; + + float mouth = cartoonEllipse(mouthUV, vec2(0.0), vec2(mouthWidth, mouthHeight)); + + // Combine features + float face = max(max(leftEye, rightEye), mouth); + face = max(face, max(leftHighlight, rightHighlight)); + + // Add border falloff + face *= smoothstep(1.2, 0.8, length(faceUV)); + + return face; +} + +float calculateSmoke(vec2 uv, vec2 sourcePos) { + float verticalDisp = (uv.y - sourcePos.y) * VERTICAL_BIAS; + vec2 smokeUV = uv * SMOKE_SCALE; + smokeUV.y -= iTime * SMOKE_SPEED * (1.0 + verticalDisp); + smokeUV.x += sin(iTime * 0.5 + uv.y * 4.0) * 0.1; + + float n = noise(smokeUV) * 0.5 + 0.5; + n += noise(smokeUV * 2.0 + iTime * 0.1) * 0.25; + + float verticalFalloff = 1.0 - smoothstep(0.0, SMOKE_RISE_HEIGHT, verticalDisp); + return n * verticalFalloff; +} + +float isTargetPixel(vec2 uv) { + vec4 color = texture(iChannel0, uv); + return float(all(lessThan(abs(color.rgb - TARGET_COLOR), vec3(COLOR_TOLERANCE)))); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord/iResolution.xy; + vec4 originalColor = texture(iChannel0, uv); + + // Calculate smoke effect + float smokeAccum = 0.0; + float targetInfluence = 0.0; + + float stepSize = SMOKE_RADIUS / 4.0; + for (float x = -SMOKE_RADIUS; x <= SMOKE_RADIUS; x += stepSize) { + for (float y = -SMOKE_RADIUS; y <= 0.0; y += stepSize) { + vec2 offset = vec2(x, y); + vec2 sampleUV = uv + offset; + + if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 && + sampleUV.y >= 0.0 && sampleUV.y <= 1.0) { + float isTarget = isTargetPixel(sampleUV); + if (isTarget > 0.0) { + float dist = length(offset); + float falloff = 1.0 - smoothstep(0.0, SMOKE_RADIUS, dist); + float smoke = calculateSmoke(uv, sampleUV); + smokeAccum += smoke * falloff; + targetInfluence += falloff; + } + } + } + } + + smokeAccum /= max(targetInfluence, 1.0); + targetInfluence = smoothstep(0.0, 1.0, targetInfluence); + float smokePresence = smokeAccum * targetInfluence; + + // Calculate ghost faces with backgrounds + float faceAccum = 0.0; + float bgAccum = 0.0; + float timeBlock = floor(iTime / FACE_DURATION); + + if (smokePresence > 0.2) { + for (int i = 0; i < FACE_COUNT; i++) { + vec2 facePos = random2(timeBlock + float(i) * 1234.5); + facePos = facePos * 0.8 + 0.1; + + float faceTime = mod(iTime, FACE_DURATION); + float fadeFactor = smoothstep(0.0, FACE_TRANSITION, faceTime) * + (1.0 - smoothstep(FACE_DURATION - FACE_TRANSITION, FACE_DURATION, faceTime)); + + // Add ghost background + float ghostBg = ghostBackground(uv, facePos) * fadeFactor; + bgAccum = max(bgAccum, ghostBg); + + // Add face features + float face = ghostFace(uv, facePos, iTime, timeBlock + float(i) * 100.0) * fadeFactor; + faceAccum = max(faceAccum, face); + } + + bgAccum *= smoothstep(0.2, 0.4, smokePresence); + faceAccum *= smoothstep(0.2, 0.4, smokePresence); + } + + // Combine all elements + bool isTarget = all(lessThan(abs(originalColor.rgb - TARGET_COLOR), vec3(COLOR_TOLERANCE))); + vec3 baseColor = isTarget ? REPLACE_COLOR : originalColor.rgb; + + // Layer the effects: base -> smoke -> ghost background -> face features + vec3 smokeEffect = mix(baseColor, SMOKE_COLOR, smokeAccum * SMOKE_INTENSITY * targetInfluence * (1.0 - faceAccum)); + vec3 withBackground = mix(smokeEffect, GHOST_BG_COLOR, bgAccum * 0.7); + vec3 finalColor = mix(withBackground, FACE_COLOR, faceAccum); + + float alpha = mix(originalColor.a, ALPHA_MAX, max(smokePresence, max(bgAccum, faceAccum) * smokePresence)); + + fragColor = vec4(finalColor, alpha); +} diff --git a/ghostty/shaders/sparks-from-fire.glsl b/ghostty/shaders/sparks-from-fire.glsl new file mode 100644 index 0000000..e48b6e1 --- /dev/null +++ b/ghostty/shaders/sparks-from-fire.glsl @@ -0,0 +1,242 @@ +// adapted by Alex Sherwin for Ghstty from https://www.shadertoy.com/view/wl2Gzc + +//Shader License: CC BY 3.0 +//Author: Jan Mróz (jaszunio15) + +#define SMOKE_INTENSITY_MULTIPLIER 0.9 +#define PARTICLES_ALPHA_MOD 0.9 +#define SMOKE_ALPHA_MOD 0.5 +#define LAYERS_COUNT 8 + +#define BLACK_BLEND_THRESHOLD .4 + +#define VEC3_1 (vec3(1.0)) + +#define PI 3.1415927 +#define TWO_PI 6.283185 + +#define ANIMATION_SPEED 1.0 +#define MOVEMENT_SPEED .33 +#define MOVEMENT_DIRECTION vec2(0.7, 1.0) + +#define PARTICLE_SIZE 0.0025 + +#define PARTICLE_SCALE (vec2(0.5, 1.6)) +#define PARTICLE_SCALE_VAR (vec2(0.25, 0.2)) + +#define PARTICLE_BLOOM_SCALE (vec2(0.5, 0.8)) +#define PARTICLE_BLOOM_SCALE_VAR (vec2(0.3, 0.1)) + +#define SPARK_COLOR vec3(1.0, 0.4, 0.05) * 1.5 +#define BLOOM_COLOR vec3(1.0, 0.4, 0.05) * 0.8 +#define SMOKE_COLOR vec3(1.0, 0.43, 0.1) * 0.8 + +#define SIZE_MOD 1.05 + + +float hash1_2(in vec2 x) +{ + return fract(sin(dot(x, vec2(52.127, 61.2871))) * 521.582); +} + +vec2 hash2_2(in vec2 x) +{ + return fract(sin(x * mat2x2(20.52, 24.1994, 70.291, 80.171)) * 492.194); +} + +//Simple interpolated noise +vec2 noise2_2(vec2 uv) +{ + //vec2 f = fract(uv); + vec2 f = smoothstep(0.0, 1.0, fract(uv)); + + vec2 uv00 = floor(uv); + vec2 uv01 = uv00 + vec2(0,1); + vec2 uv10 = uv00 + vec2(1,0); + vec2 uv11 = uv00 + 1.0; + vec2 v00 = hash2_2(uv00); + vec2 v01 = hash2_2(uv01); + vec2 v10 = hash2_2(uv10); + vec2 v11 = hash2_2(uv11); + + vec2 v0 = mix(v00, v01, f.y); + vec2 v1 = mix(v10, v11, f.y); + vec2 v = mix(v0, v1, f.x); + + return v; +} + +//Simple interpolated noise +float noise1_2(in vec2 uv) +{ + vec2 f = fract(uv); + //vec2 f = smoothstep(0.0, 1.0, fract(uv)); + + vec2 uv00 = floor(uv); + vec2 uv01 = uv00 + vec2(0,1); + vec2 uv10 = uv00 + vec2(1,0); + vec2 uv11 = uv00 + 1.0; + + float v00 = hash1_2(uv00); + float v01 = hash1_2(uv01); + float v10 = hash1_2(uv10); + float v11 = hash1_2(uv11); + + float v0 = mix(v00, v01, f.y); + float v1 = mix(v10, v11, f.y); + float v = mix(v0, v1, f.x); + + return v; +} + + +float layeredNoise1_2(in vec2 uv, in float sizeMod, in float alphaMod, in int layers, in float animation) +{ + float noise = 0.0; + float alpha = 1.0; + float size = 1.0; + vec2 offset; + for (int i = 0; i < layers; i++) + { + offset += hash2_2(vec2(alpha, size)) * 10.0; + + //Adding noise with movement + noise += noise1_2(uv * size + iTime * animation * 8.0 * MOVEMENT_DIRECTION * MOVEMENT_SPEED + offset) * alpha; + alpha *= alphaMod; + size *= sizeMod; + } + + noise *= (1.0 - alphaMod)/(1.0 - pow(alphaMod, float(layers))); + return noise; +} + +//Rotates point around 0,0 +vec2 rotate(in vec2 point, in float deg) +{ + float s = sin(deg); + float c = cos(deg); + return mat2x2(s, c, -c, s) * point; +} + +//Cell center from point on the grid +vec2 voronoiPointFromRoot(in vec2 root, in float deg) +{ + vec2 point = hash2_2(root) - 0.5; + float s = sin(deg); + float c = cos(deg); + point = mat2x2(s, c, -c, s) * point * 0.66; + point += root + 0.5; + return point; +} + +//Voronoi cell point rotation degrees +float degFromRootUV(in vec2 uv) +{ + return iTime * ANIMATION_SPEED * (hash1_2(uv) - 0.5) * 2.0; +} + +vec2 randomAround2_2(in vec2 point, in vec2 range, in vec2 uv) +{ + return point + (hash2_2(uv) - 0.5) * range; +} + + +vec3 fireParticles(in vec2 uv, in vec2 originalUV) +{ + vec3 particles = vec3(0.0); + vec2 rootUV = floor(uv); + float deg = degFromRootUV(rootUV); + vec2 pointUV = voronoiPointFromRoot(rootUV, deg); + float dist = 2.0; + float distBloom = 0.0; + + //UV manipulation for the faster particle movement + vec2 tempUV = uv + (noise2_2(uv * 2.0) - 0.5) * 0.1; + tempUV += -(noise2_2(uv * 3.0 + iTime) - 0.5) * 0.07; + + //Sparks sdf + dist = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_SCALE, PARTICLE_SCALE_VAR, rootUV)); + + //Bloom sdf + distBloom = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_BLOOM_SCALE, PARTICLE_BLOOM_SCALE_VAR, rootUV)); + + //Add sparks + particles += (1.0 - smoothstep(PARTICLE_SIZE * 0.6, PARTICLE_SIZE * 3.0, dist)) * SPARK_COLOR; + + //Add bloom + particles += pow((1.0 - smoothstep(0.0, PARTICLE_SIZE * 6.0, distBloom)) * 1.0, 3.0) * BLOOM_COLOR; + + //Upper disappear curve randomization + float border = (hash1_2(rootUV) - 0.5) * 2.0; + float disappear = 1.0 - smoothstep(border, border + 0.5, originalUV.y); + + //Lower appear curve randomization + border = (hash1_2(rootUV + 0.214) - 1.8) * 0.7; + float appear = smoothstep(border, border + 0.4, originalUV.y); + + return particles * disappear * appear; +} + + +//Layering particles to imitate 3D view +vec3 layeredParticles(in vec2 uv, in float sizeMod, in float alphaMod, in int layers, in float smoke) +{ + vec3 particles = vec3(0); + float size = 1.0; + // float alpha = 1.0; + float alpha = 1.0; + vec2 offset = vec2(0.0); + vec2 noiseOffset; + vec2 bokehUV; + + for (int i = 0; i < layers; i++) + { + //Particle noise movement + noiseOffset = (noise2_2(uv * size * 2.0 + 0.5) - 0.5) * 0.15; + + //UV with applied movement + bokehUV = (uv * size + iTime * MOVEMENT_DIRECTION * MOVEMENT_SPEED) + offset + noiseOffset; + + //Adding particles if there is more smoke, remove smaller particles + particles += fireParticles(bokehUV, uv) * alpha * (1.0 - smoothstep(0.0, 1.0, smoke) * (float(i) / float(layers))); + + //Moving uv origin to avoid generating the same particles + offset += hash2_2(vec2(alpha, alpha)) * 10.0; + + alpha *= alphaMod; + size *= sizeMod; + } + + return particles; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = (2.0 * fragCoord - iResolution.xy) / iResolution.x; + + // float vignette = 1.1 - smoothstep(0.4, 1.4, length(uv + vec2(0.0, 0.3))); + float vignette = 1.3 - smoothstep(0.4, 1.4, length(uv + vec2(0.0, 0.3))); + + uv *= 2.5; + + float smokeIntensity = layeredNoise1_2(uv * 10.0 + iTime * 4.0 * MOVEMENT_DIRECTION * MOVEMENT_SPEED, 1.7, 0.7, 6, 0.2); + smokeIntensity *= pow(smoothstep(-1.0, 1.6, uv.y), 2.0); + vec3 smoke = smokeIntensity * SMOKE_COLOR * vignette * SMOKE_INTENSITY_MULTIPLIER * SMOKE_ALPHA_MOD; + + //Cutting holes in smoke + smoke *= pow(layeredNoise1_2(uv * 4.0 + iTime * 0.5 * MOVEMENT_DIRECTION * MOVEMENT_SPEED, 1.8, 0.5, 3, 0.2), 2.0) * 1.5; + + vec3 particles = layeredParticles(uv, SIZE_MOD, PARTICLES_ALPHA_MOD, LAYERS_COUNT, smokeIntensity); + + vec3 col = particles + smoke + SMOKE_COLOR * 0.02; + col *= vignette; + + col = smoothstep(-0.08, 1.0, col); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb, col, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/spotlight.glsl b/ghostty/shaders/spotlight.glsl new file mode 100644 index 0000000..19f457a --- /dev/null +++ b/ghostty/shaders/spotlight.glsl @@ -0,0 +1,42 @@ +// Created by Paul Robello + + +// Smooth oscillating function that varies over time +float smoothOscillation(float t, float frequency, float phase) { + return sin(t * frequency + phase); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + // Resolution and UV coordinates + vec2 uv = fragCoord.xy / iResolution.xy; + + // Used to fix distortion when calculating distance to circle center + vec2 ratio = vec2(iResolution.x / iResolution.y, 1.0); + + // Get the texture from iChannel0 + vec4 texColor = texture(iChannel0, uv); + + // Spotlight center moving based on a smooth random pattern + float time = iTime * 1.0; // Control speed of motion + vec2 spotlightCenter = vec2( + 0.5 + 0.4 * smoothOscillation(time, 1.0, 0.0), // Smooth X motion + 0.5 + 0.4 * smoothOscillation(time, 1.3, 3.14159) // Smooth Y motion with different frequency and phase + ); + + // Distance from the spotlight center + float distanceToCenter = distance(uv * ratio, spotlightCenter); + + // Spotlight intensity based on distance + float spotlightRadius = 0.25; // Spotlight radius + float softness = 20.0; // Spotlight edge softness. Higher values have sharper edge + float spotlightIntensity = smoothstep(spotlightRadius, spotlightRadius - (1.0 / softness), distanceToCenter); + + // Ambient light level + float ambientLight = 0.5; // Controls the minimum brightness across the texture + + // Combine the spotlight effect with the texture + vec3 spotlightEffect = texColor.rgb * mix(vec3(ambientLight), vec3(1.0), spotlightIntensity); + + // Final color output + fragColor = vec4(spotlightEffect, texColor.a); +} \ No newline at end of file diff --git a/ghostty/shaders/starfield-colors.glsl b/ghostty/shaders/starfield-colors.glsl new file mode 100644 index 0000000..cf125a9 --- /dev/null +++ b/ghostty/shaders/starfield-colors.glsl @@ -0,0 +1,145 @@ +// divisions of grid +const float repeats = 30.; + +// number of layers +const float layers = 21.; + +// star colours +const vec3 blue = vec3(51.,64.,195.)/255.; +const vec3 cyan = vec3(117.,250.,254.)/255.; +const vec3 white = vec3(255.,255.,255.)/255.; +const vec3 yellow = vec3(251.,245.,44.)/255.; +const vec3 red = vec3(247,2.,20.)/255.; + +// spectrum function +vec3 spectrum(vec2 pos){ + pos.x *= 4.; + vec3 outCol = vec3(0); + if( pos.x > 0.){ + outCol = mix(blue, cyan, fract(pos.x)); + } + if( pos.x > 1.){ + outCol = mix(cyan, white, fract(pos.x)); + } + if( pos.x > 2.){ + outCol = mix(white, yellow, fract(pos.x)); + } + if( pos.x > 3.){ + outCol = mix(yellow, red, fract(pos.x)); + } + + return 1.-(pos.y * (1.-outCol)); +} + +float N21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +vec2 N22(vec2 p) { + float n = N21(p); + return vec2(n, N21(p + n)); +} + +mat2 scale(vec2 _scale) { + return mat2(_scale.x, 0.0, + 0.0, _scale.y); +} + +// 2D Noise based on Morgan McGuire +float noise(in vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + // Four corners in 2D of a tile + float a = N21(i); + float b = N21(i + vec2(1.0, 0.0)); + float c = N21(i + vec2(0.0, 1.0)); + float d = N21(i + vec2(1.0, 1.0)); + + // Smooth Interpolation + vec2 u = f * f * (3.0 - 2.0 * f); // Cubic Hermite Curve + + // Mix 4 corners percentages + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; +} + +float perlin2(vec2 uv, int octaves, float pscale) { + float col = 1.; + float initScale = 4.; + for (int l; l < octaves; l++) { + float val = noise(uv * initScale); + if (col <= 0.01) { + col = 0.; + break; + } + val -= 0.01; + val *= 0.5; + col *= val; + initScale *= pscale; + } + return col; +} + +vec3 stars(vec2 uv, float offset) { + float timeScale = -(iTime + offset) / layers; + float trans = fract(timeScale); + float newRnd = floor(timeScale); + vec3 col = vec3(0.); + + // Translate uv then scale for center + uv -= vec2(0.5); + uv = scale(vec2(trans)) * uv; + uv += vec2(0.5); + + // Create square aspect ratio + uv.x *= iResolution.x / iResolution.y; + + // Create boxes + uv *= repeats; + + // Get position + vec2 ipos = floor(uv); + + // Return uv as 0 to 1 + uv = fract(uv); + + // Calculate random xy and size + vec2 rndXY = N22(newRnd + ipos * (offset + 1.)) * 0.9 + 0.05; + float rndSize = N21(ipos) * 100. + 200.; + + vec2 j = (rndXY - uv) * rndSize; + float sparkle = 1. / dot(j, j); + + // Set stars to be pure white + col += spectrum(fract(rndXY*newRnd*ipos)) * vec3(sparkle); + + col *= smoothstep(1., 0.8, trans); + return col; // Return pure white stars only +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord/iResolution.xy; + + vec3 col = vec3(0.); + + for (float i = 0.; i < layers; i++ ){ + col += stars(uv, i); + } + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb, col, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); + +} diff --git a/ghostty/shaders/starfield.glsl b/ghostty/shaders/starfield.glsl new file mode 100644 index 0000000..d5fa23c --- /dev/null +++ b/ghostty/shaders/starfield.glsl @@ -0,0 +1,125 @@ +// 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 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); + } + + + // Output to screen + // fragColor = vec4(col,1.0); + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb, col, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); + +} diff --git a/ghostty/shaders/tft.glsl b/ghostty/shaders/tft.glsl new file mode 100644 index 0000000..3d77443 --- /dev/null +++ b/ghostty/shaders/tft.glsl @@ -0,0 +1,23 @@ +/** Size of TFT "pixels" */ +float resolution = 4.0; + +/** Strength of effect */ +float strength = 0.5; + +void _scanline(inout vec3 color, vec2 uv) +{ + float scanline = step(1.2, mod(uv.y * iResolution.y, resolution)); + float grille = step(1.2, mod(uv.x * iResolution.x, resolution)); + color *= max(1.0 - strength, scanline * grille); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + vec3 color = texture(iChannel0, uv).rgb; + + _scanline(color, uv); + + fragColor.xyz = color; + fragColor.w = 1.0; +} diff --git a/ghostty/shaders/underwater.glsl b/ghostty/shaders/underwater.glsl new file mode 100644 index 0000000..8c2fb22 --- /dev/null +++ b/ghostty/shaders/underwater.glsl @@ -0,0 +1,74 @@ +// adapted by Alex Sherwin for Ghostty from https://www.shadertoy.com/view/lljGDt + +#define BLACK_BLEND_THRESHOLD .4 + +float hash21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +float rayStrength(vec2 raySource, vec2 rayRefDirection, vec2 coord, float seedA, float seedB, float speed) +{ + vec2 sourceToCoord = coord - raySource; + float cosAngle = dot(normalize(sourceToCoord), rayRefDirection); + + // Add subtle dithering based on screen coordinates + float dither = hash21(coord) * 0.015 - 0.0075; + + float ray = clamp( + (0.45 + 0.15 * sin(cosAngle * seedA + iTime * speed)) + + (0.3 + 0.2 * cos(-cosAngle * seedB + iTime * speed)) + dither, + 0.0, 1.0); + + // Smoothstep the distance falloff + float distFade = smoothstep(0.0, iResolution.x, iResolution.x - length(sourceToCoord)); + return ray * mix(0.5, 1.0, distFade); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + + uv.y = 1.0 - uv.y; + vec2 coord = vec2(fragCoord.x, iResolution.y - fragCoord.y); + + // Set the parameters of the sun rays + vec2 rayPos1 = vec2(iResolution.x * 0.7, iResolution.y * 1.1); + vec2 rayRefDir1 = normalize(vec2(1.0, 0.116)); + float raySeedA1 = 36.2214; + float raySeedB1 = 21.11349; + float raySpeed1 = 1.1; + + vec2 rayPos2 = vec2(iResolution.x * 0.8, iResolution.y * 1.2); + vec2 rayRefDir2 = normalize(vec2(1.0, -0.241)); + const float raySeedA2 = 22.39910; + const float raySeedB2 = 18.0234; + const float raySpeed2 = 0.9; + + // Calculate the colour of the sun rays on the current fragment + vec4 rays1 = + vec4(1.0, 1.0, 1.0, 0.0) * + rayStrength(rayPos1, rayRefDir1, coord, raySeedA1, raySeedB1, raySpeed1); + + vec4 rays2 = + vec4(1.0, 1.0, 1.0, 0.0) * + rayStrength(rayPos2, rayRefDir2, coord, raySeedA2, raySeedB2, raySpeed2); + + vec4 col = rays1 * 0.5 + rays2 * 0.4; + + // Attenuate brightness towards the bottom, simulating light-loss due to depth. + // Give the whole thing a blue-green tinge as well. + float brightness = 1.0 - (coord.y / iResolution.y); + col.r *= 0.05 + (brightness * 0.8); + col.g *= 0.15 + (brightness * 0.6); + col.b *= 0.3 + (brightness * 0.5); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, col.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/water.glsl b/ghostty/shaders/water.glsl new file mode 100644 index 0000000..c240b58 --- /dev/null +++ b/ghostty/shaders/water.glsl @@ -0,0 +1,35 @@ + +#define TAU 6.28318530718 +#define MAX_ITER 6 + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec3 water_color = vec3(1.0, 1.0, 1.0) * 0.5; + float time = iTime * 0.5+23.0; + vec2 uv = fragCoord.xy / iResolution.xy; + + vec2 p = mod(uv*TAU, TAU)-250.0; + vec2 i = vec2(p); + float c = 1.0; + float inten = 0.005; + + for (int n = 0; n < MAX_ITER; n++) + { + float t = time * (1.0 - (3.5 / float(n+1))); + i = p + vec2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x)); + c += 1.0/length(vec2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten))); + } + c /= float(MAX_ITER); + c = 1.17-pow(c, 1.4); + vec3 color = vec3(pow(abs(c), 15.0)); + color = clamp((color + water_color)*1.2, 0.0, 1.0); + + // perterb uv based on value of c from caustic calc above + vec2 tc = vec2(cos(c)-0.75,sin(c)-0.75)*0.04; + uv = clamp(uv + tc,0.0,1.0); + + fragColor = texture(iChannel0, uv); + // give transparent pixels a color + if ( fragColor.a == 0.0 ) fragColor=vec4(1.0,1.0,1.0,1.0); + fragColor *= vec4(color, 1.0); +} \ No newline at end of file diff --git a/sketchybar/.DS_Store b/sketchybar/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..16158bd2522bad64d0df2d9db7b8cb8594245518 GIT binary patch literal 6148 zcmeHKO-~a+7=8zew0y_{Enw7SV=pEUr4VC?2TQ>i;sL@EECDRL+i6)@X6o*iiiD(B z{R3W2`~fCjyy_3oqgN090WY5MosY^#^{5fEZ!`0}^M1_7vzeI=0FXkxoC7cbAc;j_ zq6e#Ai13TjCLP++g-B!{9xwpm> zV7YN51+}(lrxDg1Uq-)kYQ7gnlarrGM`xnzLN`ip_olVY8&+gT^{`+E>!P*7x$m@e z+gbH!qhzG#IE!qL(Lg46Wr`si4?R}qjRLQ;awu~xV14`L?HSo%dl}bpX;t73CjOGU1_m_C+MIL8s z8*=oB?k=zj#}UO07Hh&4uF@bxY|AOG*+F2lDlP19`nE&;MONTZ#CMAxu0qUQ4r$eF z*JIV}-EWG^R5pKIX$E9l^d{3SO(V&^ue_4_3ge7o(vtFI^AB`L62@T`EZBf2(1e%p z8s5MM_yk|!I~r-FV{b?W}DrY|Ro)s{k zvnqN-Rv(100~8`~VH@_r0UHARx$0K?xhvjc?8#k$&2uN3rDX59n|VCpn1PsqKh1zR zA51I)^BS89<TmMn+nl`LR2cEN+tSut!;}FcddzK3yTmD*HkD|u+rDDRK!(0hD8ecOrap=H8vHZ1ttC?AZduJn1R2_ Fzz@q9=pg_A literal 0 HcmV?d00001 diff --git a/sketchybar/plugins/aerospace.sh b/sketchybar/plugins/aerospace.sh new file mode 100755 index 0000000..fad182f --- /dev/null +++ b/sketchybar/plugins/aerospace.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +if [ "$1" = "$FOCUSED_WORKSPACE" ]; then + sketchybar --set $NAME label.color=0xffcba6f7 +else + sketchybar --set $NAME label.color=0x77cdd6f4 +fi diff --git a/sketchybar/plugins/battery.sh b/sketchybar/plugins/battery.sh new file mode 100755 index 0000000..9dd9627 --- /dev/null +++ b/sketchybar/plugins/battery.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +PERCENTAGE="$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1)" +CHARGING="$(pmset -g batt | grep 'AC Power')" + +if [ "$PERCENTAGE" = "" ]; then + exit 0 +fi + +case "${PERCENTAGE}" in + 9[0-9]|100) ICON="" + ;; + [6-8][0-9]) ICON="" + ;; + [3-5][0-9]) ICON="" + ;; + [1-2][0-9]) ICON="" + ;; + *) ICON="" +esac + +if [[ "$CHARGING" != "" ]]; then + ICON="" +fi + +# The item invoking this script (name $NAME) will get its icon and label +# updated with the current battery status +sketchybar --set "$NAME" icon="$ICON" label="${PERCENTAGE}%" diff --git a/sketchybar/plugins/clock.sh b/sketchybar/plugins/clock.sh new file mode 100755 index 0000000..ff2b445 --- /dev/null +++ b/sketchybar/plugins/clock.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# The $NAME variable is passed from sketchybar and holds the name of +# the item invoking this script: +# https://felixkratz.github.io/SketchyBar/config/events#events-and-scripting + +sketchybar --set "$NAME" label="$(date '+%A, %d %b, %I:%M %p')" + diff --git a/sketchybar/plugins/front_app.sh b/sketchybar/plugins/front_app.sh new file mode 100755 index 0000000..fb6d0b3 --- /dev/null +++ b/sketchybar/plugins/front_app.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Some events send additional information specific to the event in the $INFO +# variable. E.g. the front_app_switched event sends the name of the newly +# focused application in the $INFO variable: +# https://felixkratz.github.io/SketchyBar/config/events#events-and-scripting + +if [ "$SENDER" = "front_app_switched" ]; then + sketchybar --set "$NAME" label="$INFO" +fi diff --git a/sketchybar/plugins/space.sh b/sketchybar/plugins/space.sh new file mode 100755 index 0000000..b8602b5 --- /dev/null +++ b/sketchybar/plugins/space.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# The $SELECTED variable is available for space components and indicates if +# the space invoking this script (with name: $NAME) is currently selected: +# https://felixkratz.github.io/SketchyBar/config/components#space----associate-mission-control-spaces-with-an-item + +sketchybar --set "$NAME" background.drawing="$SELECTED" diff --git a/sketchybar/plugins/volume.sh b/sketchybar/plugins/volume.sh new file mode 100755 index 0000000..6e69a5d --- /dev/null +++ b/sketchybar/plugins/volume.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# The volume_change event supplies a $INFO variable in which the current volume +# percentage is passed to the script. + +if [ "$SENDER" = "volume_change" ]; then + VOLUME="$INFO" + + case "$VOLUME" in + [6-9][0-9]|100) ICON="󰕾" + ;; + [3-5][0-9]) ICON="󰖀" + ;; + [1-9]|[1-2][0-9]) ICON="󰕿" + ;; + *) ICON="󰖁" + esac + + sketchybar --set "$NAME" icon="$ICON" label="$VOLUME%" +fi diff --git a/sketchybar/plugins/wifi.sh b/sketchybar/plugins/wifi.sh new file mode 100755 index 0000000..788cb9b --- /dev/null +++ b/sketchybar/plugins/wifi.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# Get the current Wi-Fi SSID +wifi_name=$(networksetup -listpreferredwirelessnetworks en0 | sed -n '2 p' | tr -d '\t') + +# If the Wi-Fi name is empty, set a default value (e.g., "No Wi-Fi") +if [ -z "$wifi_name" ]; then + wifi_name="Offline" +fi + +# Set the Wi-Fi name as the label in SketchyBar +sketchybar --set "$NAME" label="$wifi_name" diff --git a/sketchybar/sketchybarrc b/sketchybar/sketchybarrc new file mode 100755 index 0000000..c90183a --- /dev/null +++ b/sketchybar/sketchybarrc @@ -0,0 +1,128 @@ +#!/usr/bin/env bash + +# === CONFIG ROOT === +CONFIG_DIR="$HOME/.config/sketchybar" +PLUGIN_DIR="$CONFIG_DIR/plugins" + +# === COLORS === +CLR_BG=0x00000000 # Transparent bar background +CLR_COMP_BG=0xff1e1e2e # Compartment background (Mocha base) +CLR_COMP_BORDER=0xff313244 # Compartment border (Mocha surface0) +CLR_FG=0xffcdd6f4 +CLR_MAUVE=0xffcba6f7 +CLR_BLUE=0xff89b4fa +CLR_GREEN=0xffa6e3a1 +CLR_RED=0xfff38ba8 +CLR_YELLOW=0xfff9e2af +CLR_TEAL=0xff94e2d5 +CLR_SUBTEXT=0xff6c7086 # Mocha surface2, good for secondary text + +# === PADDING CONSTANTS +BAR_PADDING=8 # Outer bar padding (use compartments for outer spacing) +ITEM_PADDING=6 # Default horizontal padding between items +ICON_PADDING=2 # Consistent icon inner padding (reduced from mixed 2/4 for tighter look) +LABEL_PADDING=2 # Consistent label inner padding (unified from 4/2) +COMP_PADDING=6 # Compartment outer padding (increased from bar-level 0 for breathing room) + +# === SYSTEM METRICS PROVIDER === +#pkill -f stats_provider >/dev/null 2>&1 +#/Users/nate/Documents/scripts/stats_provider --cpu temperature & + +# === BAR (No outer padding; defer to compartments) === +sketchybar --bar position=top height=34 blur_radius=0 color="$CLR_BG" padding_left="$BAR_PADDING" padding_right="$BAR_PADDING" + +# === WORKSPACES === +sketchybar --add event aerospace_workspace_change +LABELS=("" "" "" "" "" "" "󰖣" "" "󰎇") +LEFT_SPACE_ITEMS=() +INDEX=0 + +for sid in $(aerospace list-workspaces --all); do + label="${LABELS[$INDEX]:-}" + item="space.$sid" + LEFT_SPACE_ITEMS+=("$item") + + sketchybar --add item "$item" left \ + --subscribe "$item" aerospace_workspace_change \ + --set "$item" \ + background.color=0xff000000 \ + background.corner_radius=5 \ + background.height=20 \ + background.drawing=off \ + label="$label" \ + icon.padding_left="$ICON_PADDING" \ + icon.padding_right="$ICON_PADDING" \ + label.padding_left="$LABEL_PADDING" \ + label.padding_right="$LABEL_PADDING" \ + click_script="aerospace workspace $sid" \ + script="$PLUGIN_DIR/aerospace.sh $sid" + + ((INDEX++)) +done + +# === DEFAULTS (Unified paddings for all items/icons/labels) === +sketchybar --default \ + padding_left="$ITEM_PADDING" \ + padding_right="$ITEM_PADDING" \ + icon.font="VictorMono Nerd Font:Regular:12.0" \ + label.font="VictorMono Nerd Font:Regular:15.0" \ + icon.color="$CLR_FG" \ + label.color="$CLR_FG" \ + icon.padding_left="$ICON_PADDING" \ + icon.padding_right="$ICON_PADDING" \ + label.padding_left="$LABEL_PADDING" \ + label.padding_right="$LABEL_PADDING" + +# === FRONT APP +sketchybar --add item front_app left \ + --set front_app \ + script="$PLUGIN_DIR/front_app.sh" \ + label.y_offset=1 \ + label.padding_right="$COMP_PADDING" \ + --subscribe front_app front_app_switched + +# === RIGHT SIDE ITEMS === +sketchybar --add item clock right \ + --set clock update_freq=10 icon= script="$PLUGIN_DIR/clock.sh" label.padding_right="$COMP_PADDING" + +sketchybar --add item volume right \ + --set volume script="$PLUGIN_DIR/volume.sh" \ + --subscribe volume volume_change + +sketchybar --add item battery right \ + --set battery update_freq=120 script="$PLUGIN_DIR/battery.sh" \ + --subscribe battery system_woke power_source_change + +sketchybar --add item net right \ + --set net update_freq=120 icon= script="$PLUGIN_DIR/wifi.sh" + +# sketchybar --add item cpu_temp right \ + # --set cpu_temp icon= script="sketchybar --set cpu_temp label=\$CPU_TEMP" icon.padding_left="$COMP_PADDING" \ + # --subscribe cpu_temp system_stats + +# === ITEM GROUPS === +LEFT_ITEMS=("${LEFT_SPACE_ITEMS[@]}" front_app) +RIGHT_ITEMS=(clock volume battery net cpu_temp) + +# === COMPARTMENTS (Outer padding for clean edges; height=26 leaves vertical margin in 34pt bar) === +sketchybar --add bracket left_compartment "${LEFT_ITEMS[@]}" \ + --set left_compartment \ + background.color="$CLR_COMP_BG" \ + background.corner_radius=8 \ + background.height=26 \ + background.border_color="$CLR_COMP_BORDER" \ + background.border_width=1 \ + background.drawing=on + +sketchybar --add bracket right_compartment "${RIGHT_ITEMS[@]}" \ + --set right_compartment \ + background.color="$CLR_COMP_BG" \ + background.corner_radius=8 \ + background.height=26 \ + background.border_color="$CLR_COMP_BORDER" \ + background.border_width=1 \ + background.padding_left=0 \ + background.drawing=on + +# === FINALIZE === +sketchybar --update diff --git a/starship.toml b/starship.toml new file mode 100644 index 0000000..6c0c03a --- /dev/null +++ b/starship.toml @@ -0,0 +1,68 @@ +add_newline = true +command_timeout = 2000 + +format = """$env_var$os$username$hostname$kubernetes$directory$git_branch$git_status$python +$character +""" + +[character] +success_symbol = "[╰⎯](#a78bfa)" +error_symbol = "[╰⎯](#a78bfa)" + +[env_var] +symbol = "[╭╴](#a78bfa)" +variable = 'SHELL' +format = "$symbol" +disabled = false + +[os] +format = '[$symbol](#a78bfa bold) ' +disabled = false + +[os.symbols] +Windows = ' ' +Arch = '󰣇' +Ubuntu = '' +Macos = '󰀵' +Unknown = '󰠥' + +[username] +style_user = 'bold' +style_root = 'bold' +format = '[//](#a78bfa) [$user](#8e59c5) ' +disabled = false +show_always = true + +[hostname] +ssh_only = false +format = '[//](#a78bfa) [$hostname](#e879f9 bold) ' +disabled = false + +[directory] +truncation_length = 0 +truncation_symbol = '…/' +home_symbol = '~' +read_only = '  ' +format = '[//](#a78bfa) [$path](#f472b6 bold)[$read_only](#f472b6) ' +style = '#f472b6' + +[git_branch] +symbol = ' ' +format = '[//](#a78bfa) [$symbol\[$branch\]](#e879f9 bold) ' +style = '#e879f9 bold' + +[git_status] +disabled = true +format = '[ $all_status $ahead_behind](#f472b6) ' +style = '#f472b6' + +[kubernetes] +format = 'via [󱃾 $context\($namespace\)](#c084fc bold) ' +disabled = false + +[python] +symbol = '󰌠' +python_binary = ['./venv/bin/python', 'python', 'python3', 'python2'] +format = '[//](#a78bfa) [$symbol $pyenv_prefix($version )($virtualenv )](#e879f9 bold) ' + +