# yazi-gruvbox A [Gruvbox Dark](https://github.com/morhetz/gruvbox) `theme.toml` for [Yazi](https://github.com/sxyazi/yazi) — including the **icon table**, so the devicons in front of your files stop looking like a paint spill on an otherwise muted colour scheme. Written against **Yazi 26.9**. It uses the current schema (`[mgr]`, `[tabs]`, `[pick]`, `[cmp]`, `[indicator]`, …), not the pre-25.x one — older Gruvbox themes floating around still use `[manager]` and `[select]` and will throw errors on a current Yazi. ## What it covers Panel chrome, status bar, tabs, mode indicator, which-key, confirm/spot/notify popups, picker, input, completion, task manager, help — plus: **File and directory names** (`[filetype]`): | | | |---|---| | directories | `#83a598` blue | | regular files | `#ebdbb2` fg1 | | executables | `#b8bb26` green | | archives | `#fe8019` orange | | images | `#fabd2f` yellow | | audio / video | `#d3869b` purple | | PDF / doc | `#8ec07c` aqua | | orphan symlinks | red background | **Icons** (`[icon]`): all 725 entries of Yazi's preset table, every glyph colour remapped to its nearest Gruvbox tone. **Syntax highlighting** (`gruvbox-dark.tmTheme`): 39 scope rules for the file preview, written from scratch against [morhetz/gruvbox](https://github.com/morhetz/gruvbox)'s own vim highlight links — comments gray italic, strings green, constants purple, keywords red, identifiers blue, functions green bold, types yellow, preprocessor aqua, operators plain foreground. ## How the icon colours were derived Yazi's preset ships 725 icon entries using 221 distinct colours from the nvim-tree/devicons palette — saturated web colours that clash badly with Gruvbox's muted ground. `regen-icons.py` maps each of them onto the Gruvbox palette: - **Nearest neighbour in Oklab**, so the match is perceptual rather than a naive RGB distance. - **Lightness weighted down (0.7)** in the distance metric, so *hue* drives the result. Docker blue stays blue, Ruby red stays red, instead of everything collapsing toward whatever tone happens to be equally bright. - **Chromatic and greyish sources are matched from separate pools** (split at Oklab chroma 0.04). Without that split a vivid magenta can land on grey, and white can land on orange. - **Low-contrast targets are excluded.** `#cc241d` (2.69:1) and `#7c6f64` (3.03:1) on `#282828` were dropped from the target palette — icons are non-text, so 3:1 is the bar. The dimmest icon now sits at **3.48:1**. 221 colours end up on 19 Gruvbox tones. Icons stay colourful and stay distinguishable; they just stop shouting. ## Install ```sh git clone https://git.opennerds.org/templis/yazi-gruvbox cp yazi-gruvbox/theme.toml yazi-gruvbox/gruvbox-dark.tmTheme ~/.config/yazi/ ``` `theme.toml` overrides Yazi's built-in `theme-dark.toml`; anything it does not set keeps the default. Both files are needed — `theme.toml` points at the `.tmTheme` for syntax highlighting in file previews. ## Sharper previews (optional) Not part of the colour scheme, but it belongs in the same corner of `~/.config/yazi` — the files are under `preview/`. ```sh cp preview/yazi.toml ~/.config/yazi/yazi.toml cp -r preview/plugins/pdf-hidpi.yazi ~/.config/yazi/plugins/ ya cache clear ``` ### Why PDFs look mushy by default Two bottlenecks stack up: 1. Yazi calls `pdftoppm` **without `-r`**, so pages render at poppler's 150 DPI default — an A4 page is 1241x1754 px. 2. `[preview] max_width` / `max_height` default to **600x900**. The page is squeezed to 600 px wide and then scaled back up to fill the pane. On top of that the page is JPEG-compressed at quality 75, which smears glyph edges. `preview/yazi.toml` raises the cap to 1600x2400, and the `pdf-hidpi` plugin is Yazi's own PDF previewer with two changes: `-r 300` and PNG instead of JPEG. The page now renders at 2481x3508 and is downscaled into the cap, so the result is supersampled rather than upscaled — and lossless where the glyphs are. **Both the previewer and the preloader must be overridden.** They write the same cache file, so replacing only one leaves the 150 DPI version in place. `preview/yazi.toml` does both. Yazi has no zoom. What it has is `J` / `K`, which turn PDF pages in the preview, and whatever key you bound to maximise the preview pane. ### Videos The video preview is **one still frame** by design: `ffmpeg` pulls a keyframe at 5 % of the runtime and Yazi shows it as an image. Nothing animates, and no setting changes that. What does work: | Key | | |---|---| | `J` / `K` | scrub the preview through the file, ±5 % per press | | `Tab` | spot panel — codec, resolution, duration | | `Enter` / `o` | open in an mpv window | | `O` | pick an opener — including **Play here (Kitty)** | The last one is the `[opener]` block in `preview/yazi.toml`: it runs `mpv --vo=kitty --vo-kitty-use-shm=yes`, which draws the video into the terminal pane through the Kitty graphics protocol. Yazi blocks until mpv exits (`q`). Shared-memory transfer keeps it watchable; without it every frame goes through the tty as base64 and it crawls. It is still a terminal doing a framebuffer's job — fine for checking what a clip is, not for watching it. Defining `play` replaces Yazi's preset list rather than merging into it, which is why mpv appears twice there: once windowed, once inline. ## Keeping the icon table current The `[icon]` block **replaces** Yazi's preset table wholesale. Icons added by later Yazi releases will not show up until it is regenerated: ```sh git clone --depth 1 https://github.com/sxyazi/yazi awk '/^\[icon\]/{f=1} f' yazi/yazi-config/preset/theme-dark.toml > icons-src.toml ./regen-icons.py icons-src.toml # writes icon-gruvbox.toml ``` Then replace the `[icon]` block in `theme.toml` with the generated file. The script prints which Gruvbox tone each source colour landed on. `regen-tmtheme.py` does the same for `gruvbox-dark.tmTheme` — edit the palette or the scope rules at the top of the script and re-run it. Both generators and the `pdf-hidpi` plugin target the **26.9** plugin API. If you build against Yazi's `main` branch instead of the tag you run, you will hit renamed functions — `fs.cha()` was `fs.stat()` on main — and the error only surfaces at preview time. ## Self-contained Everything needed is in this repository — nothing has to be fetched from a third-party theme repo, and no file here carries a copyleft licence. ## Licence MIT — see `LICENSE`. The `.tmTheme` is original work; the derived icon data is MIT as well. Notices in `THIRD-PARTY.md`.