Skip to content

tripock/DotBrow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hyprland Logo      River WM Logo

DotBrow

Community-Driven Dotfile Repository for Wayland Tiling Window Managers

FeaturesScreenshotsGetting StartedArchitectureConfig GuideContributingFAQLicense

Hyprland River WM Wayland JavaScript CSS3 HTML5


Table of Contents


Overview

DotBrow is a self-hosted, client-side web application designed to serve as a centralized repository for browsing, sharing, and installing dotfiles (configuration files) specifically tailored for two of the most popular Wayland tiling window managers: Hyprland and River WM.

Built entirely with vanilla HTML, CSS, and JavaScript — no frameworks, no build step, no dependencies — DotBrow runs directly in any modern browser from a local file or any static hosting provider. All data persists in the browser's localStorage, making it completely serverless and privacy-respecting.

The application features a premium dark-themed interface with animated gradient backgrounds, glassmorphism effects, smooth page transitions, and a carefully crafted color system that distinguishes Hyprland (cyan/blue palette) and River WM (orange/amber palette) configurations at a glance.


Why DotBrow?

The Wayland ecosystem has grown rapidly, and with it the number of users configuring tiling window managers. However, discovering quality configurations remains fragmented across Reddit posts, GitHub gists, forum threads, and wiki pages. DotBrow addresses this by providing:

For Users:

  • A single place to browse curated Hyprland and River WM configurations
  • Visual previews of each setup before installing
  • One-click install commands or downloadable config files
  • Category-based navigation to quickly find what you need

For Creators:

  • A beautiful platform to showcase your rice/configuration
  • Two flexible install methods: shell commands or raw dotfile content
  • Image preview uploads to show off your desktop
  • Source URL linking back to your GitHub/GitLab repository

For the Community:

  • Zero server infrastructure — runs entirely client-side
  • No accounts, no tracking, no analytics
  • Completely open source and self-hostable
  • Works offline after first load

Features

Category System

DotBrow organizes all dotfiles into two primary categories, each with its own visual identity:

Category Primary Color Accent Icon
Hyprland #00b4d8 (Cyan) #0077b6 (Deep Blue) Official Hyprland SVG logo
River WM #f77f00 (Orange) #e36414 (Deep Orange) Official River WM SVG logo

Each category features:

  • Dedicated card on the home page with dotfile count
  • Color-coded navigation in the header
  • Themed section headers on category pages
  • Empty state messaging when no dotfiles exist
  • Dynamic upload button that changes color to match the active category

Upload System

The upload modal provides a comprehensive form for adding new dotfiles:

Field Type Required Description
Name Text input Yes Display name for the dotfile (max 100 chars)
Preview Image File/Drag-drop No Screenshot of the configuration (max 5MB, image/* types)
Source URL URL input Yes Link to the source repository or gist
Category Select dropdown Yes Hyprland or River WM
Install Method Button toggle Yes CMD Install (blue) or Dotfile Installer (orange)
Install Command Text input Conditional Shell command (shown when CMD Install is selected)
Dotfile Content Textarea Conditional Raw config content (shown when Dotfile Installer is selected)

The upload form features:

  • Real-time field validation with error messages
  • Drag-and-drop image preview with FileReader API
  • Animated field reveal when selecting install method
  • Submit button that changes color based on install method selection
  • Auto-selection of current category when uploading from a category page
  • Form reset on modal open/close

Install Methods

DotBrow supports two distinct installation approaches, each with its own color coding:

CMD Install (Blue — #2196f3)

For configurations that require running a shell command to install. This is ideal for:

  • Install scripts that clone a git repository and symlink files
  • curl | bash one-liner installers
  • Package manager commands (pacman, yay, paru, etc.)
  • Makefile-based installations
  • stow-based dotfile managers

When a user clicks the install button on a CMD-type card, the command is revealed in a monospace code block. Clicking the code block copies it to the clipboard with a visual tooltip confirmation.

Example commands:

git clone https://github.com/user/dotfiles && cd dotfiles && make install
curl -sL https://raw.githubusercontent.com/user/dotfiles/main/install.sh | bash
yay -S hyprland-dots-git

Dotfile Installer (Orange — #ff9800)

For configurations distributed as raw text content. This is ideal for:

  • Single-file configurations (hyprland.conf, init for river)
  • Minimal configs that don't need an installer
  • Config snippets and modules
  • Theme files and color schemes

When a user clicks the install button on a Dotfile-type card, the raw content is packaged into a .conf file and downloaded via the browser's download API using Blob and URL.createObjectURL.

Card Grid Layout

Dotfile cards are displayed in a responsive CSS Grid layout:

Grid: repeat(auto-fill, minmax(340px, 1fr))
Gap: 20px
Padding: 0 48px 60px

Each card contains:

  • Preview area (200px height) — either the uploaded image or a placeholder icon
  • Delete button — appears on hover in the top-right corner of the preview
  • Card body with:
    • Name + type badge (CMD blue or DOTFILE orange)
    • Source URL with link icon
    • Install button (color-coded by type)
    • Expandable command text (CMD type only)

Cards feature staggered entrance animations with incrementing delays (0.07s per card) for a cascading reveal effect.

Animations & Transitions

DotBrow employs a comprehensive animation system:

Animation Duration Easing Usage
orbFloat 20s ease-in-out Background gradient orbs
gradientShift 4s ease-in-out Hero title gradient
pulse 2s ease-in-out Status badge dot
fadeInUp 0.6s ease-out Page content entrance
cardAppear 0.5s ease-out Dotfile card entrance
toastIn 0.4s spring Toast notification enter
toastOut 0.3s ease-in Toast notification exit

Page transitions use a three-phase system:

  1. Exit: Active page slides left with opacity fade (translateX(-40px), opacity: 0)
  2. Delay: 200ms pause for visual separation
  3. Enter: New page slides in from right (translateX(40px)translateY(0), opacity: 1)

Transition timing uses CSS custom properties:

  • --transition-fast: 0.2s cubic-bezier(0.4, 0, 0.2, 1)
  • --transition-normal: 0.3s cubic-bezier(0.4, 0, 0.2, 1)
  • --transition-slow: 0.5s cubic-bezier(0.4, 0, 0.2, 1)
  • --transition-spring: 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)

Theme & Design

The visual design follows these principles:

  • Dark-first: #0a0a0f base with layered transparency
  • Glassmorphism: backdrop-filter: blur() on header, modals, and toasts
  • Animated backgrounds: Three floating gradient orbs with parallax motion
  • Subtle grid overlay: 60px grid lines at 2% opacity for depth
  • Color consistency: Each WM category has a dedicated gradient, glow, and accent
  • Typography: Inter font family with weights 300–900, JetBrains Mono for code

Screenshots

To add screenshots, place them in the repository root and reference them here.

screenshots/
├── home.png          # Landing page with category cards
├── hyprland.png      # Hyprland category with dotfile cards
├── river.png         # River WM category with dotfile cards
├── upload-modal.png  # Upload form with CMD Install selected
├── card-hover.png    # Card hover state with delete button
└── mobile.png        # Responsive mobile layout

Getting Started

Prerequisites

DotBrow has zero build dependencies. You need:

  • A modern web browser (Chrome 88+, Firefox 85+, Safari 15+, Edge 88+)
  • Any method to serve static files (optional — works from file:// protocol)

That's it. No Node.js, no npm, no bundler, no transpiler.

Installation

git clone https://github.com/yourusername/dotbrow.git
cd dotbrow

The repository contains exactly these files:

dotbrow/
├── index.html        # Main HTML document (single page application)
├── style.css         # Complete CSS design system (~1300 lines)
├── app.js            # Application logic (~700 lines)
├── hyprland.svg      # Official Hyprland logo
├── riverwm.svg       # Official River WM logo
└── README.md         # This documentation

Running Locally

Option 1: Direct file open

xdg-open index.html
# or
firefox index.html
# or
google-chrome index.html

Option 2: Python HTTP server

python3 -m http.server 8080
# Open http://localhost:8080

Option 3: PHP built-in server

php -S localhost:8080

Option 4: Node.js (if installed)

npx serve .
# or
npx http-server -p 8080

Option 5: Caddy

caddy file-server --listen :8080

Deploying

DotBrow is a static site — deploy it anywhere that serves HTML:

GitHub Pages

  1. Push the repository to GitHub
  2. Go to Settings → Pages
  3. Select the branch (usually main) and root directory
  4. Your site will be live at https://username.github.io/dotbrow/

Netlify

  1. Connect your Git repository
  2. Build command: (leave empty)
  3. Publish directory: .
  4. Deploy

Vercel

npx vercel --prod

Cloudflare Pages

  1. Connect repository
  2. Framework preset: None
  3. Build command: (leave empty)
  4. Output directory: .

Nginx Configuration

server {
    listen 80;
    server_name dotbrow.example.com;
    root /var/www/dotbrow;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location ~* \.(css|js|svg|png|jpg|webp|ico)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    gzip on;
    gzip_types text/html text/css application/javascript image/svg+xml;
}

Apache .htaccess

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ index.html [QSA,L]
</IfModule>

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 30 days"
    ExpiresByType application/javascript "access plus 30 days"
    ExpiresByType image/svg+xml "access plus 30 days"
</IfModule>

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript image/svg+xml
</IfModule>

Architecture

Project Structure

dotbrow/
│
├── index.html                 # Single-page application entry point
│   ├── <head>                 # Meta tags, CSS import, favicon
│   ├── .bg-canvas             # Animated background layer (orbs + grid)
│   ├── .app-header            # Fixed navigation header
│   │   ├── .app-header__logo  # Logo with dual SVG icons
│   │   └── .app-header__nav   # Navigation buttons + upload
│   ├── .page-container        # Page transition container
│   │   ├── #page-home         # Home page with hero + category cards
│   │   └── #page-category     # Category page with grid + back button
│   ├── #upload-modal          # Upload modal overlay
│   │   └── .modal             # Modal content with form
│   └── .toast-container       # Toast notification stack
│
├── style.css                  # Complete design system
│   ├── CSS Variables           # ~50 design tokens
│   ├── Reset & Base           # Box-sizing, font smoothing
│   ├── Background             # Animated orbs, grid overlay
│   ├── Header                 # Fixed nav, logo, buttons
│   ├── Pages & Transitions    # Page enter/exit animations
│   ├── Hero Section           # Landing page content
│   ├── Category Cards         # Home page category selection
│   ├── Section Headers        # Category page headers
│   ├── Dotfile Grid           # Card grid layout
│   ├── Dotfile Cards          # Individual card styling
│   ├── Empty State            # No-data messaging
│   ├── Modal                  # Upload overlay + form
│   ├── Form Controls          # Inputs, selects, buttons
│   ├── Toasts                 # Notification styling
│   ├── Scrollbar              # Custom scrollbar styling
│   └── Media Queries          # Responsive breakpoints
│
├── app.js                     # Application logic (IIFE)
│   ├── Storage Layer          # localStorage CRUD
│   ├── State Variables        # currentPage, currentCategory
│   ├── DOM Helpers            # $, $$, escapeHtml
│   ├── Toast System           # showToast, auto-dismiss
│   ├── Navigation             # navigateTo, updateNavButtons
│   ├── Rendering              # renderHome, renderCategory
│   ├── Card Builder           # renderDotfileCard
│   ├── Upload System          # Modal, validation, submit
│   ├── Image Handler          # FileReader, drag-and-drop
│   ├── Clipboard              # copy with fallback
│   ├── File Download          # Blob-based download
│   └── Init                   # Event binding, initial render
│
├── hyprland.svg               # Hyprland project logo (gradient)
└── riverwm.svg                # River WM project logo (monochrome)

Technology Stack

Layer Technology Rationale
Structure HTML5 Semantic markup, accessibility
Styling CSS3 Custom properties, Grid, Flexbox, animations, backdrop-filter
Logic Vanilla JavaScript (ES5+) Zero dependencies, maximum compatibility
Storage localStorage Client-side persistence, no server needed
Fonts Google Fonts (Inter, JetBrains Mono) Modern typography, excellent readability
Icons Unicode + SVG No icon library dependency
Images Base64 Data URLs Embedded in localStorage, no file hosting

Data Model

Each dotfile entry is stored as a JSON object in the dotbrow_dotfiles localStorage key:

{
  "id": "m1abc2def3ghi",
  "name": "Catppuccin Hyprland",
  "sourceUrl": "https://github.com/user/dotfiles",
  "previewImage": "data:image/png;base64,...",
  "category": "hyprland",
  "installType": "cmd",
  "installCommand": "git clone https://github.com/user/dotfiles && cd dotfiles && stow hyprland",
  "dotfileContent": null,
  "createdAt": "2026-04-11T12:00:00.000Z"
}
Field Type Nullable Description
id string No Unique identifier (timestamp base36 + random)
name string No Display name (1–100 characters)
sourceUrl string No URL to source repository
previewImage string Yes Base64 Data URL of preview image
category "hyprland" | "river" No Window manager category
installType "cmd" | "dotfile" No Installation method
installCommand string Yes Shell command (only when installType === "cmd")
dotfileContent string Yes Raw config text (only when installType === "dotfile")
createdAt string No ISO 8601 timestamp

State Management

The application uses three module-scoped variables for state:

let currentPage = 'home';       // 'home' | 'category'
let currentCategory = null;     // 'hyprland' | 'river' | null
let uploadImageData = null;     // Base64 string | null

State transitions:

HOME ──[click card]──────> CATEGORY(hyprland)
HOME ──[click card]──────> CATEGORY(river)
HOME ──[click nav btn]───> CATEGORY(hyprland)
HOME ──[click nav btn]───> CATEGORY(river)
CATEGORY ──[click back]──> HOME
CATEGORY ──[click logo]──> HOME
CATEGORY ──[click nav]───> CATEGORY(other)

Page Navigation System

Navigation is handled by the navigateTo(page, category) function which orchestrates a multi-step transition:

1. Mark current page as exiting (add 'page--exit-left')
2. Remove 'page--active' from current page
3. Wait 200ms
4. Clear all page state classes
5. Add 'page--enter-right' to target page
6. On next animation frame:
   - Remove 'page--enter-right'
   - Add 'page--active'
7. Call appropriate render function
8. Update navigation button states
9. Update upload button color

This creates a smooth slide-left-exit → slide-right-enter transition between pages.

Storage Layer

The storage layer wraps localStorage with JSON serialization and error handling:

loadDotfiles()   → JSON.parse(localStorage.getItem(key)) → Array
saveDotfiles(arr) → localStorage.setItem(key, JSON.stringify(arr))

Storage limitations:

  • localStorage typically allows 5–10MB per origin
  • Base64 images increase storage usage (~33% overhead vs raw binary)
  • Large preview images (5MB limit enforced) could fill storage quickly
  • Consider using IndexedDB for larger deployments (not implemented)

Configuration Guide

This section provides comprehensive guidance on configuring Hyprland and River WM, helping users understand what dotfiles they might want to browse or upload.

Hyprland Configuration Basics

Hyprland uses a custom configuration format stored at ~/.config/hypr/hyprland.conf. The configuration is divided into sections:

# Monitor configuration
monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1

# Autostart applications
exec-once = waybar
exec-once = hyprpaper
exec-once = mako
exec-once = wl-paste --type text --watch cliphist store

# Environment variables
env = XCURSOR_SIZE, 24
env = QT_QPA_PLATFORMTHEME, qt6ct
env = GDK_BACKEND, wayland,x11
env = QT_QPA_PLATFORM, wayland;xcb

# Input configuration
input {
    kb_layout = us,ru
    kb_options = grp:alt_shift_toggle
    follow_mouse = 1
    sensitivity = 0
    touchpad {
        natural_scroll = true
        tap-to-click = true
        drag_lock = true
    }
}

# General appearance
general {
    gaps_in = 5
    gaps_out = 10
    border_size = 2
    col.active_border = rgba(00b4d8ff) rgba(0077b6ff) 45deg
    col.inactive_border = rgba(595959aa)
    layout = dwindle
    allow_tearing = false
}

# Decorations
decoration {
    rounding = 10
    blur {
        enabled = true
        size = 8
        passes = 3
        new_optimizations = true
        xray = false
    }
    drop_shadow = true
    shadow_range = 15
    shadow_render_power = 3
    col.shadow = rgba(1a1a1aee)
    active_opacity = 1.0
    inactive_opacity = 0.92
}

# Animations
animations {
    enabled = true
    bezier = overshot, 0.13, 0.99, 0.29, 1.1
    bezier = smoothOut, 0.36, 0, 0.66, -0.56
    bezier = smoothIn, 0.25, 1, 0.5, 1
    animation = windows, 1, 5, overshot, slide
    animation = windowsOut, 1, 4, smoothOut, slide
    animation = border, 1, 10, default
    animation = borderangle, 1, 8, default
    animation = fade, 1, 10, smoothIn
    animation = fadeDim, 1, 10, smoothIn
    animation = workspaces, 1, 6, overshot, slidevert
}

# Layout configuration
dwindle {
    pseudotile = true
    preserve_split = true
    force_split = 2
    smart_split = false
    smart_resizing = true
}

master {
    new_status = master
    orientation = left
    mfact = 0.55
}

Hyprland Modules Explained

Hyprland's configuration can be split into modular files for better organization:

~/.config/hypr/
├── hyprland.conf          # Main config (sources others)
├── monitors.conf          # Monitor layout
├── autostart.conf         # exec-once commands
├── environment.conf       # env variables
├── input.conf             # Keyboard, mouse, touchpad
├── appearance.conf        # general, decoration, animations
├── layouts.conf           # dwindle, master settings
├── keybinds.conf          # All key bindings
├── windowrules.conf       # Window rules and layers
└── plugins.conf           # Plugin configuration

Source them from the main config:

source = ~/.config/hypr/monitors.conf
source = ~/.config/hypr/autostart.conf
source = ~/.config/hypr/environment.conf
source = ~/.config/hypr/input.conf
source = ~/.config/hypr/appearance.conf
source = ~/.config/hypr/layouts.conf
source = ~/.config/hypr/keybinds.conf
source = ~/.config/hypr/windowrules.conf
source = ~/.config/hypr/plugins.conf

River WM Configuration Basics

River uses an executable init file at ~/.config/river/init. This is typically a shell script:

#!/bin/sh

# Appearance
riverctl background-color 0x0a0a0f
riverctl border-color-focused 0xf77f00
riverctl border-color-unfocused 0x333333
riverctl border-width 2

# Keyboard repeat rate
riverctl set-repeat 50 300

# Keyboard layout
riverctl keyboard-layout -options "grp:alt_shift_toggle" "us,ru"

# Focus follows mouse
riverctl focus-follows-cursor normal

# Cursor warp on focus change
riverctl set-cursor-warp on-focus-change

# Default layout generator
riverctl default-layout rivertile

# Rivertile layout settings
rivertile -view-padding 5 -outer-padding 5 -main-ratio 0.55 -main-count 1 &

# Autostart
waybar &
mako &
hyprpaper &
wl-paste --type text --watch cliphist store &

# Key bindings - general
riverctl map normal Super Return spawn foot
riverctl map normal Super D spawn "wofi --show drun"
riverctl map normal Super Q close
riverctl map normal Super+Shift E exit

# Key bindings - focus
riverctl map normal Super J focus-view next
riverctl map normal Super K focus-view previous

# Key bindings - swap
riverctl map normal Super+Shift J swap next
riverctl map normal Super+Shift K swap previous

# Key bindings - layout
riverctl map normal Super H send-layout-cmd rivertile "main-ratio -0.05"
riverctl map normal Super L send-layout-cmd rivertile "main-ratio +0.05"
riverctl map normal Super+Shift H send-layout-cmd rivertile "main-count +1"
riverctl map normal Super+Shift L send-layout-cmd rivertile "main-count -1"

# Key bindings - workspaces (tags in river)
for i in $(seq 1 9); do
    tags=$((1 << ($i - 1)))
    riverctl map normal Super $i set-focused-tags $tags
    riverctl map normal Super+Shift $i set-view-tags $tags
    riverctl map normal Super+Control $i toggle-focused-tags $tags
    riverctl map normal Super+Shift+Control $i toggle-view-tags $tags
done

# Float & fullscreen
riverctl map normal Super Space toggle-float
riverctl map normal Super F toggle-fullscreen

# Screenshots
riverctl map normal Super Print spawn 'grim -g "$(slurp)" - | wl-copy'
riverctl map normal None Print spawn 'grim - | wl-copy'

# Audio
riverctl map normal None XF86AudioRaiseVolume spawn "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
riverctl map normal None XF86AudioLowerVolume spawn "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
riverctl map normal None XF86AudioMute spawn "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"

# Brightness
riverctl map normal None XF86MonoBrightnessUp spawn "brightnessctl set +5%"
riverctl map normal None XF86MonoBrightnessDown spawn "brightnessctl set 5%-"

# Window rules
riverctl rule-add -app-id "firefox" ssd
riverctl rule-add -app-id "pavucontrol" float
riverctl rule-add -app-id "nm-connection-editor" float
riverctl rule-add -app-id "thunar" float
riverctl rule-add -title "Picture-in-Picture" float

# Input configuration
for pad in $(riverctl list-inputs | grep -i touchpad); do
    riverctl input $pad natural-scroll enabled
    riverctl input $pad tap enabled
    riverctl input $pad disable-while-typing enabled
done

River WM Layout System

River uses external layout generators, making it uniquely flexible:

Built-in: rivertile

rivertile -view-padding 6 -outer-padding 6 -main-ratio 0.55 -main-count 1 &

Alternative: rivercarro (more features)

rivercarro -inner-gaps 6 -outer-gaps 6 -main-ratio 0.55 -main-count 1 &

Alternative: stacktile (stacking layout)

stacktile --per-tag-config --primary-count 1 --primary-ratio 0.55 &

Custom layout generators can be written in any language that supports the Wayland river-layout-v3 protocol.

Common Wayland Utilities

These utilities are commonly referenced in Hyprland and River WM dotfiles:

Utility Purpose Config Location
waybar Status bar ~/.config/waybar/
eww Widget system ~/.config/eww/
mako Notifications ~/.config/mako/config
dunst Notifications (alt) ~/.config/dunst/dunstrc
wofi Application launcher ~/.config/wofi/
fuzzel Application launcher ~/.config/fuzzel/fuzzel.ini
tofi Application launcher ~/.config/tofi/config
rofi-wayland Application launcher ~/.config/rofi/
swaylock Screen locker ~/.config/swaylock/config
hyprlock Screen locker (Hypr) ~/.config/hypr/hyprlock.conf
swayidle Idle daemon inline config
hypridle Idle daemon (Hypr) ~/.config/hypr/hypridle.conf
hyprpaper Wallpaper ~/.config/hypr/hyprpaper.conf
swaybg Wallpaper inline config
mpvpaper Video wallpaper inline config
swww Animated wallpaper inline config
grim Screenshot inline config
slurp Region selector inline config
wf-recorder Screen recorder inline config
wl-clipboard Clipboard inline config
cliphist Clipboard history inline config

Bar & Status Programs

Waybar is the most popular choice. Example config structure:

~/.config/waybar/
├── config.jsonc       # Bar layout and modules
├── style.css          # Visual styling
└── scripts/           # Custom module scripts
    ├── weather.sh
    ├── media.sh
    └── updates.sh

EWW (Elkowar's Wacky Widgets):

~/.config/eww/
├── eww.yuck           # Widget definitions
├── eww.scss           # Styling
└── scripts/           # Data provider scripts

Notification Daemons

Mako minimal config:

# ~/.config/mako/config
default-timeout=5000
border-size=2
border-color=#00b4d8
border-radius=8
background-color=#12121aee
text-color=#e8e8ef
font=Inter 11
width=350
height=150
margin=10
padding=15
icons=1
max-icon-size=48
layer=overlay
anchor=top-right

Dunst config reference:

# ~/.config/dunst/dunstrc
[global]
    width = 350
    height = 150
    offset = 10x50
    origin = top-right
    transparency = 10
    frame_color = "#00b4d8"
    font = Inter 11
    corner_radius = 8
    background = "#12121a"
    foreground = "#e8e8ef"

[urgency_low]
    background = "#12121a"
    foreground = "#8b8b9e"
    frame_color = "#55556a"

[urgency_normal]
    background = "#12121a"
    foreground = "#e8e8ef"
    frame_color = "#00b4d8"

[urgency_critical]
    background = "#12121a"
    foreground = "#f44336"
    frame_color = "#f44336"

Application Launchers

Wofi config:

# ~/.config/wofi/config
show=drun
width=500
height=400
location=center
allow_images=true
image_size=32
columns=1
hide_scroll=true
insensitive=true
prompt=Search...
layer=overlay

Fuzzel config:

# ~/.config/fuzzel/fuzzel.ini
[main]
font=Inter:size=12
dpi-aware=auto
prompt=""
layer=overlay
width=45
horizontal-pad=20
vertical-pad=10
inner-pad=5

[colors]
background=12121aee
text=e8e8efff
match=00b4d8ff
selection=ffffff15
selection-text=e8e8efff
border=ffffff15

[border]
width=2
radius=12

Screen Lock & Idle

Hyprlock configuration:

# ~/.config/hypr/hyprlock.conf
background {
    monitor =
    path = /home/user/wallpaper.png
    blur_passes = 3
    blur_size = 8
    noise = 0.02
    contrast = 0.9
    brightness = 0.7
    vibrancy = 0.2
}

input-field {
    monitor =
    size = 250, 50
    outline_thickness = 2
    dots_size = 0.2
    dots_spacing = 0.3
    dots_center = true
    outer_color = rgba(0, 180, 216, 0.5)
    inner_color = rgba(18, 18, 26, 0.8)
    font_color = rgb(232, 232, 239)
    fade_on_empty = true
    placeholder_text = <i>Password...</i>
    hide_input = false
    position = 0, -20
    halign = center
    valign = center
}

label {
    monitor =
    text = $TIME
    color = rgba(232, 232, 239, 1.0)
    font_size = 64
    font_family = Inter
    position = 0, 100
    halign = center
    valign = center
}

Hypridle configuration:

# ~/.config/hypr/hypridle.conf
general {
    lock_cmd = pidof hyprlock || hyprlock
    before_sleep_cmd = loginctl lock-session
    after_sleep_cmd = hyprctl dispatch dpms on
}

listener {
    timeout = 300
    on-timeout = brightnessctl -s set 10
    on-resume = brightnessctl -r
}

listener {
    timeout = 600
    on-timeout = loginctl lock-session
}

listener {
    timeout = 900
    on-timeout = hyprctl dispatch dpms off
    on-resume = hyprctl dispatch dpms on
}

Wallpaper Managers

Hyprpaper:

# ~/.config/hypr/hyprpaper.conf
preload = ~/Pictures/wallpaper.png
wallpaper = , ~/Pictures/wallpaper.png
splash = false
ipc = on

SWWW (animated wallpapers):

# In autostart
swww-daemon &
sleep 0.5
swww img ~/Pictures/wallpaper.png --transition-type grow --transition-pos center --transition-duration 2

Terminal Emulators

Popular Wayland-native terminals and their config paths:

Terminal Config Path Notable Features
foot ~/.config/foot/foot.ini Fast, minimal, sixel support
kitty ~/.config/kitty/kitty.conf GPU-rendered, ligatures
alacritty ~/.config/alacritty/alacritty.toml GPU-rendered, minimal
wezterm ~/.config/wezterm/wezterm.lua Lua config, multiplexer

Foot example:

# ~/.config/foot/foot.ini
[main]
font=JetBrains Mono:size=11
dpi-aware=yes
pad=10x10

[colors]
background=0a0a0f
foreground=e8e8ef
regular0=1a1a2e
regular1=f44336
regular2=4caf50
regular3=ff9800
regular4=2196f3
regular5=9c27b0
regular6=00b4d8
regular7=8b8b9e
bright0=55556a
bright1=ff5252
bright2=69f0ae
bright3=ffab40
bright4=448aff
bright5=ce93d8
bright6=18ffff
bright7=e8e8ef

[cursor]
color=0a0a0f e8e8ef
blink=yes

Screenshot & Recording

Grim + Slurp keybind setup (common in both WMs):

# Full screen to clipboard
grim - | wl-copy

# Region to clipboard
grim -g "$(slurp)" - | wl-copy

# Full screen to file
grim ~/Pictures/Screenshots/$(date +%Y%m%d_%H%M%S).png

# Region to file
grim -g "$(slurp)" ~/Pictures/Screenshots/$(date +%Y%m%d_%H%M%S).png

# Active window (Hyprland)
grim -g "$(hyprctl activewindow -j | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')" - | wl-copy

wf-recorder:

# Record full screen
wf-recorder -f ~/Videos/recording.mp4

# Record region
wf-recorder -g "$(slurp)" -f ~/Videos/recording.mp4

# Record with audio
wf-recorder --audio -f ~/Videos/recording.mp4

Clipboard Managers

Cliphist setup:

# Store clipboard in history (add to autostart)
wl-paste --type text --watch cliphist store &
wl-paste --type image --watch cliphist store &

# Show history (bind to a key)
cliphist list | wofi --show dmenu | cliphist decode | wl-copy

# Clear history
cliphist wipe

Audio Management

WirePlumber / PipeWire volume controls:

# Raise volume
wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+

# Lower volume
wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-

# Mute toggle
wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle

# Microphone mute
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle

Display & Monitor Configuration

Hyprland multi-monitor:

monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1
monitor = eDP-1, preferred, auto, 1

# Workspace assignment
workspace = 1, monitor:DP-1
workspace = 2, monitor:DP-1
workspace = 3, monitor:HDMI-A-1

River multi-monitor:

# Use wlr-randr or kanshi for output management
kanshi &

Kanshi auto-profile config:

# ~/.config/kanshi/config
profile docked {
    output DP-1 mode 2560x1440@144 position 0,0
    output HDMI-A-1 mode 1920x1080@60 position 2560,0
}

profile undocked {
    output eDP-1 mode 1920x1080@60 position 0,0
}

Input Configuration

libinput touchpad settings (used by both WMs):

# River
riverctl input pointer-*-Touchpad natural-scroll enabled
riverctl input pointer-*-Touchpad tap enabled
riverctl input pointer-*-Touchpad disable-while-typing enabled
riverctl input pointer-*-Touchpad click-method clickfinger
riverctl input pointer-*-Touchpad scroll-method two-finger
# Hyprland
input {
    touchpad {
        natural_scroll = true
        tap-to-click = true
        disable_while_typing = true
        clickfinger_behavior = true
        scroll_method = 2fg
    }
}

GTK & Qt Theming

# GTK theme (gsettings)
gsettings set org.gnome.desktop.interface gtk-theme "Adwaita-dark"
gsettings set org.gnome.desktop.interface color-scheme "prefer-dark"
gsettings set org.gnome.desktop.interface icon-theme "Papirus-Dark"
gsettings set org.gnome.desktop.interface cursor-theme "Bibata-Modern-Classic"
gsettings set org.gnome.desktop.interface cursor-size 24
gsettings set org.gnome.desktop.interface font-name "Inter 11"

# Qt theming via environment variables
export QT_QPA_PLATFORMTHEME=qt6ct
export QT_STYLE_OVERRIDE=adwaita-dark

GTK-3.0 settings:

# ~/.config/gtk-3.0/settings.ini
[Settings]
gtk-theme-name=Adwaita-dark
gtk-icon-theme-name=Papirus-Dark
gtk-cursor-theme-name=Bibata-Modern-Classic
gtk-cursor-theme-size=24
gtk-font-name=Inter 11
gtk-application-prefer-dark-theme=true

Font Configuration

Fontconfig:

<!-- ~/.config/fontconfig/fonts.conf -->
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
    <alias>
        <family>sans-serif</family>
        <prefer><family>Inter</family></prefer>
    </alias>
    <alias>
        <family>serif</family>
        <prefer><family>Noto Serif</family></prefer>
    </alias>
    <alias>
        <family>monospace</family>
        <prefer><family>JetBrains Mono</family></prefer>
    </alias>
    <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>
</fontconfig>

Cursor Themes

Popular cursor themes for Wayland:

Theme Style Package
Bibata Modern Classic Material, filled bibata-cursor-theme
Bibata Modern Ice Material, outlined bibata-cursor-theme
Catppuccin Mocha Dark Pastel, dark catppuccin-cursors
Phinger Minimal, modern phinger-cursors
Capitaine macOS-like capitaine-cursors

Set cursor theme:

export XCURSOR_THEME=Bibata-Modern-Classic
export XCURSOR_SIZE=24

Icon Themes

Recommended icon themes:

Theme Style Package
Papirus Dark Flat, complete papirus-icon-theme
Tela Circle Circular, colorful tela-circle-icon-theme
Colloid Modern, rounded colloid-icon-theme
Kora Flat, pastel kora-icon-theme
WhiteSur macOS-like whitesur-icon-theme

CSS Design System

Color Palette

/* Backgrounds */
--bg-primary:       #0a0a0f    /* Page background */
--bg-secondary:     #12121a    /* Card/modal backgrounds */
--bg-card:          rgba(255, 255, 255, 0.04)   /* Card surface */
--bg-card-hover:    rgba(255, 255, 255, 0.08)   /* Card hover */
--bg-glass:         rgba(255, 255, 255, 0.06)   /* Glass elements */
--bg-glass-strong:  rgba(255, 255, 255, 0.1)    /* Emphasized glass */

/* Borders */
--border-glass:       rgba(255, 255, 255, 0.08)  /* Default */
--border-glass-hover: rgba(255, 255, 255, 0.15)  /* Hover/focus */

/* Text */
--text-primary:    #e8e8ef    /* Headings, primary content */
--text-secondary:  #8b8b9e    /* Body text, labels */
--text-muted:      #55556a    /* Placeholders, disabled */

/* Hyprland (Cyan) */
--hyprland-primary:    #00b4d8
--hyprland-secondary:  #0077b6
--hyprland-glow:       rgba(0, 180, 216, 0.3)

/* River WM (Orange) */
--river-primary:    #f77f00
--river-secondary:  #e36414
--river-glow:       rgba(247, 127, 0, 0.3)

/* Functional */
--cmd-blue:           #2196f3    /* CMD Install type */
--dotfile-orange:     #ff9800    /* Dotfile Install type */
--success:            #4caf50    /* Success states */
--danger:             #f44336    /* Error/delete states */

Typography

/* Primary font */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;

/* Code font */https://filip-mitish.github.io/DotBrow/
font-family: 'JetBrains Mono', monospace;

/* Weight scale */
300  /* Light - rarely used */
400  /* Regular - body text */
500  /* Medium - labels, nav */
600  /* SemiBold - buttons, badges */
700  /* Bold - card titles, headings */
800  /* ExtraBold - section titles */
900  /* Black - hero title */

Spacing & Layout

/* Border radius tokens */
--radius-sm:  8px    /* Small elements, badges */
--radius-md:  12px   /* Buttons, inputs, cards */
--radius-lg:  16px   /* Large cards */
--radius-xl:  24px   /* Modals, hero cards */

/* Shadow tokens */
--shadow-sm:  0 2px 8px rgba(0, 0, 0, 0.3)
--shadow-md:  0 4px 16px rgba(0, 0, 0, 0.4)
--shadow-lg:  0 8px 32px rgba(0, 0, 0, 0.5)
--shadow-xl:  0 16px 64px rgba(0, 0, 0, 0.6)

Glassmorphism Effects

Used on header, modals, and toasts:

background: rgba(10, 10, 15, 0.8);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);

Animation Tokens

--transition-fast:   0.2s cubic-bezier(0.4, 0, 0.2, 1)   /* Hover states */
--transition-normal: 0.3s cubic-bezier(0.4, 0, 0.2, 1)   /* Button clicks */
--transition-slow:   0.5s cubic-bezier(0.4, 0, 0.2, 1)   /* Page transitions */
--transition-spring: 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) /* Modal, toasts */

Responsive Breakpoints

/* Tablet (≤860px) */
@media (max-width: 860px) {
    /* Stack category cards vertically */
    /* Single column dotfile grid */
    /* Reduce header padding */
    /* Hide logo text */
    /* Reduce hero padding and font size */
}

/* Mobile (≤480px) */
@media (max-width: 480px) {
    /* Stack install type buttons vertically */
    /* Reduce modal border radius */
    /* Reduce modal body padding */
}

JavaScript API Reference

Storage Functions

Function Signature Returns Description
loadDotfiles () → Array Array<DotfileEntry> Load all dotfiles from localStorage
saveDotfiles (list: Array) → void void Save dotfile array to localStorage
generateId () → string string Generate unique ID (timestamp36 + random)

Navigation Functions

Function Signature Description
navigateTo (page: string, category?: string) → void Navigate with animated transition
updateNavButtons () → void Sync nav button active states
updateUploadButton () → void Sync upload button color to category

Rendering Functions

Function Signature Description
renderHome () → void Update home page dotfile counts
renderCategory (category: string) → void Render category grid with cards
renderDotfileCard (item: Object, delay: number) → string Generate card HTML string

Upload Functions

Function Signature Description
openUploadModal () → void Show modal, reset form, lock scroll
closeUploadModal () → void Hide modal, unlock scroll
resetUploadForm () → void Clear all form fields and state
handleInstallTypeSelect (type: string) → void Toggle CMD/Dotfile fields + button color
getSelectedInstallType () → string | null Get current install type selection
handlePreviewImage (file: File) → void Read and display image preview
validateAndSubmit () → void Validate form and create entry

Utility Functions

Function Signature Description
showToast (message: string, type: string) → void Show auto-dismissing notification
escapeHtml (str: string) → string Escape HTML special characters
copyToClipboard (text: string, event: Event) → void Copy text with fallback
fallbackCopy (text: string, event: Event) → void execCommand copy fallback
showCopyTooltip (event: Event) → void Show "Copied!" tooltip at cursor
downloadTextFile (filename: string, content: string) → void Download text as file
findDotfileById (id: string) → Object | null Look up dotfile entry by ID
deleteDotfile (id: string) → void Remove dotfile and re-render
getCountForCategory (cat: string) → number Count dotfiles in category

Contributing

Code Style

  • No comments in code — code should be self-documenting
  • No build tools — vanilla HTML/CSS/JS only
  • No external dependencies — no npm, no CDN libraries (except Google Fonts)
  • BEM naming for CSS classes (block__element--modifier)
  • ES5 compatible JavaScript (no arrow functions, no const/let in critical paths)
  • Explicit error handling — every DOM query should null-check
  • No innerHTML with user input without escapeHtml() — XSS prevention

Pull Request Process

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes
  4. Test in at least Chrome and Firefox
  5. Ensure no console errors
  6. Submit a pull request with a clear description
  7. Reference any related issues

Reporting Bugs

When reporting bugs, please include:

  • Browser name and version
  • Operating system
  • Steps to reproduce
  • Expected behavior
  • Actual behavior
  • Console output (if any)
  • Screenshot (if visual bug)

Feature Requests

Feature requests are welcome. Please describe:

  • The problem you're trying to solve
  • Your proposed solution
  • Alternative solutions you've considered
  • How it fits with the existing design

FAQ

Q: Where is the data stored? A: All data is stored in your browser's localStorage under the key dotbrow_dotfiles. No data is sent to any server.

Q: Can I export my dotfiles? A: Currently, you can manually export by running localStorage.getItem('dotbrow_dotfiles') in the browser console. A proper export/import feature is planned.

Q: What's the maximum number of dotfiles I can store? A: It depends on your browser's localStorage limit (typically 5–10MB). Preview images stored as Base64 take the most space. Without images, you can store thousands of entries.

Q: Can I use this with other window managers? A: DotBrow is designed for Hyprland and River WM, but the codebase can be easily extended to support additional categories like Sway, i3, dwl, etc.

Q: Does it work offline? A: Yes, after the first load (which fetches Google Fonts), everything works offline. For fully offline use, download the fonts and serve them locally.

Q: Can I share my DotBrow instance with others? A: Since data is stored in localStorage, each user has their own isolated data. To share, you would need to implement a backend or use a shared JSON file.

Q: How do preview images work? A: Images are converted to Base64 Data URLs via the FileReader API and stored directly in localStorage. This means no external image hosting is needed, but it uses more storage space.

Q: Is there a dark mode? A: DotBrow is dark-mode only by design. The dark theme with glassmorphism and gradient accents is a core part of the aesthetic.

Q: Can I self-host this? A: Absolutely. It's just static files. Put them on any web server, GitHub Pages, Netlify, Vercel, Cloudflare Pages, or even serve from a USB drive.

Q: Why vanilla JavaScript instead of React/Vue/Svelte? A: Zero dependencies means zero build step, zero supply chain risk, instant deployment, and no framework churn. The application's complexity doesn't warrant a framework.


Troubleshooting

Problem: Page is blank after opening index.html

  • Ensure all three files (index.html, style.css, app.js) are in the same directory
  • Check the browser console for errors (F12 → Console)
  • Try serving via HTTP instead of file:// protocol

Problem: Fonts look different / fallback fonts

  • Google Fonts requires internet access on first load
  • Check if your network blocks fonts.googleapis.com
  • The app gracefully falls back to system fonts

Problem: Upload button overlaps form fields

  • Report the issue with your browser version and screen resolution
  • As a workaround, scroll within the modal to see all fields

Problem: Images don't appear in preview

  • Ensure the image is under 5MB
  • Check that the file type is a valid image format
  • Try a different image format (PNG, JPEG, WebP)

Problem: localStorage is full

  • Large preview images consume the most space
  • Delete unused dotfiles or use smaller preview images
  • Run localStorage.clear() in console to reset (deletes all data)

Problem: Clipboard copy doesn't work

  • Some browsers require HTTPS for navigator.clipboard
  • The fallback execCommand('copy') should work on HTTP
  • Check browser permissions for clipboard access

Roadmap

v1.1 — Data Management

  • Export all dotfiles as JSON
  • Import dotfiles from JSON file
  • Bulk delete functionality
  • Sort dotfiles by name/date/type
  • Search within dotfiles

v1.2 — Enhanced UI

  • Dotfile preview modal (view config without downloading)
  • Syntax highlighting for config files
  • Thumbnail generation from full-size images
  • Light theme toggle
  • Custom accent color picker

v1.3 — Extended WM Support

  • Sway category
  • dwl category
  • Niri category
  • Custom category creation
  • Category icons customization

v1.4 — Collaboration

  • Share individual dotfiles via URL (encoded in hash)
  • QR code generation for dotfile sharing
  • JSON-based community repository format
  • Git-based backend option

v2.0 — Full Platform

  • Optional backend (Node.js/Go/Rust)
  • User accounts and authentication
  • Community ratings and comments
  • Dotfile versioning
  • Dependency tracking between configs
  • Live preview rendering
  • API for programmatic access

Acknowledgments

  • Hyprland — Vaxry and all contributors for creating the most visually impressive Wayland compositor
  • River — Isaac Freund for the elegant and flexible River WM
  • Inter — Rasmus Andersson for the beautiful Inter typeface
  • JetBrains Mono — JetBrains for the excellent monospace font
  • Wayland Community — All the ricers, dotfile creators, and Linux enthusiasts who make the ecosystem vibrant
  • r/unixporn — Endless inspiration for window manager configurations

License

This project is licensed under the MIT License.

MIT License

Copyright (c) 2026 DotBrow Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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 OR COPYRIGHT HOLDERS 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.

Built with ❤️ for the Wayland community

About

An repo for dotfiles of riverwm and hyprland

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors