# Font Rendering Fix — Real Session Recipe (CachyOS KDE)

**Symptom:** User reported text "looks weird, messy, not clean, very blurry or pixelated."
**Target:** CachyOS (Arch), KDE Plasma, NVIDIA RTX 3070, 3 monitors (1×LG 4K TV + 2×BenQ 1080p)
**Session model:** deepseek-v4-flash via Hermes

## Root Cause

`XftAntialias=false` in `~/.config/kdeglobals` — anti-aliasing was entirely disabled. Makes text look jagged, pixelated, and messy.

## Applied Changes (7 fixes)

| Setting | File | Before | After |
|---------|------|--------|-------|
| `XftAntialias` | `~/.config/kdeglobals` | `false` | `true` |
| `XftRGBA` | `~/.config/kdeglobals` | missing | `rgb` |
| `XftSubPixel` | `~/.config/kdeglobals` | missing | `rgb` |
| `XftHintStyle` | `~/.config/kdeglobals` | `hintslight` | `hintslight` (unchanged) |
| Font size | `~/.config/kdeglobals` | Inter 10pt | Inter 11pt |
| `FREETYPE_PROPERTIES` | `/etc/environment.d/99-font-rendering.conf` | unset | `cff:no-stem-darkening=1 autofitter:warping=1` |
| fontconfig | `~/.config/fontconfig/fonts.conf` | absent | DPI 96, lcddefault, hintslight, reject bitmap |

## Commands Used

### 1. Diagnose

```bash
# Check Xft settings (the smoking gun)
grep "Xft" ~/.config/kdeglobals

# Check KScreen for mixed DPI setup
cat ~/.local/share/kscreen/outputs/*

# Check current font
grep "^font=" ~/.config/kdeglobals
```

### 2. Fix Anti-Aliasing

```bash
sed -i 's/XftAntialias=false/XftAntialias=true/' ~/.config/kdeglobals
grep -q 'XftRGBA' ~/.config/kdeglobals \
  && sed -i 's/XftRGBA=.*/XftRGBA=rgb/' ~/.config/kdeglobals \
  || sed -i '/^\[General\]/a XftRGBA=rgb' ~/.config/kdeglobals
```

### 3. Set FREETYPE_PROPERTIES (system-wide)

```bash
sudo mkdir -p /etc/environment.d
sudo tee /etc/environment.d/99-font-rendering.conf << 'EOF'
FREETYPE_PROPERTIES="cff:no-stem-darkening=1 autofitter:warping=1"
EOF
```

### 4. Create fontconfig Local Config

```bash
mkdir -p ~/.config/fontconfig
cat > ~/.config/fontconfig/fonts.conf << 'XML'
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="pattern">
    <edit name="dpi" mode="assign"><double>96</double></edit>
  </match>
  <match target="font">
    <edit name="antialias" mode="assign"><bool>true</bool></edit>
    <edit name="hinting" mode="assign"><bool>true</bool></edit>
    <edit name="hintstyle" mode="assign"><const>hintslight</const></edit>
    <edit name="rgba" mode="assign"><const>rgb</const></edit>
    <edit name="lcdfilter" mode="assign"><const>lcddefault</const></edit>
  </match>
  <selectfont>
    <rejectfont>
      <pattern>
        <patelt name="fontformat"><string>FIXED</string></patelt>
      </pattern>
    </rejectfont>
  </selectfont>
</fontconfig>
XML
```

### 5. Bump Font Size (mixed DPI fix)

```bash
sed -i 's/^font=Inter,10,/font=Inter,11,/' ~/.config/kdeglobals
sed -i 's/^menuFont=Inter,10,/menuFont=Inter,11,/' ~/.config/kdeglobals
```

### 6. Apply

```bash
kwin_x11 --replace
# Or log out and back in
```

## Relevant freetype2 Info

On Arch/CachyOS (freetype2 2.14.3+), the package ships with ClearType-style subpixel rendering (v40 mode) built in — no patches needed. The `FREETYPE_PROPERTIES` env var controls runtime tuning:

- `cff:no-stem-darkening=1` — Disables stem darkening on CFF/OpenType fonts. Stem darkening thickens thin strokes to compensate for dark-on-light rendering, but on modern monitors with high contrast it makes text look heavier and muddier. Disabling it gives cleaner, more macOS-like text.
- `autofitter:warping=1` — Enables warping in the autofitter for crisper edge alignment. More like Windows ClearType.

## Pitfalls

- **SSH with fish shell:** On CachyOS where fish is the default shell, `bash -c 'cmd'` doesn't work because fish interprets the whole argument. Use heredoc piping: `ssh user@host bash -s <<'SSHEND'` instead.
- **`grep` may be `rg` (ripgrep):** The user installed `rg` as a grep replacement. Extended regex flags (`-E`) interpret pipe chars (`|`) inside patterns differently. Use basic grep patterns or `rg -e` for alternation.
- **`/etc/environment.d/` doesn't exist by default** on Arch/CachyOS. Must `mkdir -p` first.
- **Systemd user sessions pick up `environment.d`** — environment files work for both system-wide (`/etc/environment.d/`) and user-level (`~/.config/environment.d/`).
- **KDE QDBus tool names:** On CachyOS the tool is `qdbus-qt5` not `qdbus`. Check with `pacman -Ql qt5-tools | grep bin/qdbus` if unsure.
