A fast, customizable static site generator for creating beautiful Linktree-like pages
Genkan (Japanese for "entrance" or "foyer") is a lightweight static site generator that creates beautiful, responsive link pages similar to Linktree, but with the power of self-hosting and complete customization.
- Fast & Lightweight: Built in Rust for blazing-fast generation
- Fully Customizable: Complete control over themes, colors, and layout
- Responsive Design: Works perfectly on desktop and mobile devices
- Simple Configuration: Easy-to-use TOML configuration
- Self-Hosted: Generate static HTML - host anywhere
- Theme System: Create and share custom themes
- No Dependencies: Output is pure HTML/CSS/JS - no runtime dependencies
- Dark Mode Support: Auto, light, dark, or disabled modes with separate color schemes
- Image Compression: Automatic download, resize, and embedding of all images for faster loading
- Share Button: Built-in share button with QR code generation
- Background Images: Support for custom background images and gradients
- Customizable Footer: Option to hide or show the "Made with Genkan" footer
cargo install genkan- Rust 1.70 or higher (install from rustup.rs)
# Clone the repository
git clone https://github.com/dephilia/genkan.git
cd genkan
# Build the project
cargo build --release
# The binary will be in target/release/genkan
# Optionally, install it globally
cargo install --path .genkan init my-links
cd my-linksThis creates:
my-links/
βββ config.toml # Your configuration file
βββ themes/ # Theme directory
βββ output/ # Generated output
Open config.toml and customize it with your information:
[profile]
name = "Your Name"
bio = "Welcome to my link page! π"
avatar = "https://your-avatar-url.com/image.jpg"
[[links]]
title = "My Website"
url = "https://example.com"
icon = "π"
[[links]]
title = "Twitter"
url = "https://twitter.com/yourhandle"
icon = "π¦"genkan buildYour page is now available at output/index.html!
Simply open output/index.html in your browser, or deploy it to any static hosting service (GitHub Pages, Netlify, Vercel, etc.).
After initialization, your project will have this structure:
genkan/
βββ Cargo.toml # Rust project configuration
βββ README.md # Documentation
βββ LICENSE # MIT License
βββ config.toml # Your configuration file
βββ src/
β βββ main.rs # CLI entry point
β βββ config.rs # Configuration parser
β βββ generator.rs # Page generator
βββ themes/
β βββ simple/
β βββ template.html # HTML template
β βββ style.css # Responsive CSS
β βββ script.js # Optional JavaScript
βββ output/
βββ index.html # Generated page
Need to make quick changes? Here are the most common customizations:
Edit config.toml:
[theme]
primary_color = "#667eea"
secondary_color = "#2d3748"
background_color = "#f7fafc"Add to config.toml:
[[links]]
title = "My Link"
url = "https://example.com"
icon = "π" # emoji, URL, or omit for default
description = "Optional subtitle"Edit config.toml:
[theme]
button_style = "pill" # options: rounded, pill, squareEdit config.toml:
[profile]
# Option 1: Gradient or solid color
background = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
# Option 2: Background image (takes priority)
background_image = "https://example.com/bg.jpg"Edit config.toml:
[meta]
show_footer = false # Hide "Made with Genkan" footerEdit config.toml:
[meta]
custom_css = """
.link-button {
background: linear-gradient(90deg, #667eea, #764ba2);
}
"""The [profile] section controls your personal information:
[profile]
name = "Your Name" # Your display name
bio = "Welcome to my link page! π" # Short bio or tagline
avatar = "https://example.com/me.jpg" # Profile picture (URL or local path)
background = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)" # Optional background- URL:
avatar = "https://example.com/avatar.jpg" - Local file:
avatar = "./images/me.jpg"(relative to config.toml) - If omitted, a default icon will be shown
- Solid color:
background = "#ff6b6b" - Gradient:
background = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)" - Background image (URL):
background_image = "https://example.com/bg.jpg" - Background image (local):
background_image = "./images/background.jpg" - Note:
background_imagetakes priority overbackgroundif both are set
The [theme] section controls the visual appearance:
[theme]
name = "simple" # Theme name
primary_color = "#000000" # Primary color for buttons and accents
secondary_color = "#000000" # Secondary color for accents
background_color = "#ffffff" # Page background
button_style = "rounded" # Button shape: rounded, pill, square
font_family = "system-ui, -apple-system, sans-serif" # Font
link_spacing = "32px" # Space between links
# Legacy color domains (deprecated - use typography system instead)
header_color = "#000000" # Profile name/header color
bio_color = "rgba(0, 0, 0, 0.7)" # Bio/description text color
link_title_color = "#000000" # Link title text color
link_description_color = "rgba(0, 0, 0, 0.6)" # Link description text color- A. Header (
header_color): Profile name at the top - B. Bio/Description (
bio_color): Bio text under profile name - C. Primary Color (
primary_color): Buttons, accents, and interactive elements - D. Link Title (
link_title_color): Main text in link blocks - E. Link Description (
link_description_color): Subtitle/description in link blocks
rounded: Slightly rounded corners (12px radius)pill: Fully rounded ends (50px radius)square: Sharp corners (4px radius)
The [theme.typography] section provides granular control over text styling. Each text element (header, bio, link_title, link_description) can have its own size, font, weight, style, and color settings.
[theme.typography.default]
size = "16px"
font = "system-ui, -apple-system, sans-serif"
weight = "normal"
style = "normal"
color = "#000000"
[theme.typography.header]
size = "2rem"
# font = "" # empty or omit to use default
weight = "700"
style = "normal"
color = "#000000"
[theme.typography.bio]
size = "1.1rem"
weight = "normal"
style = "normal"
color = "rgba(0, 0, 0, 0.7)"
[theme.typography.link_title]
size = "1.1rem"
weight = "600"
style = "normal"
color = "#000000"
[theme.typography.link_description]
size = "0.9rem"
weight = "normal"
style = "italic" # Can be "normal" or "italic"
color = "rgba(0, 0, 0, 0.6)"Typography Properties:
size: Font size (e.g., "16px", "1.2rem", "1em")font: Font family (e.g., "Arial, sans-serif")weight: Font weight (e.g., "normal", "bold", "600", "700")style: Font style ("normal" or "italic")color: Text color (any valid CSS color)
Fallback Behavior:
- If a property is not specified for an element, it falls back to the
defaultvalues - If
defaultis not specified, it uses built-in defaults - For backward compatibility, the old color fields (
header_color,bio_color, etc.) are still supported
Genkan supports automatic dark mode with separate color schemes for light and dark themes:
[dark_mode]
mode = "auto" # Options: "auto", "light", "dark", "disable"
# Light mode colors
[theme.light]
primary_color = "#000000"
secondary_color = "#000000"
background_color = "#ffffff"
header_color = "#000000"
bio_color = "rgba(0, 0, 0, 0.7)"
link_title_color = "#000000"
link_description_color = "rgba(0, 0, 0, 0.6)"
# Dark mode colors
[theme.dark]
primary_color = "#ffffff"
secondary_color = "#ffffff"
background_color = "#1a1a1a"
header_color = "#ffffff"
bio_color = "rgba(255, 255, 255, 0.7)"
link_title_color = "#ffffff"
link_description_color = "rgba(255, 255, 255, 0.6)"
# Optional: Separate avatars for light and dark mode
[profile.light]
avatar = "https://example.com/avatar-light.png"
[profile.dark]
avatar = "https://example.com/avatar-dark.png"Dark Mode Options:
auto: Automatically switch based on system preference (default)light: Force light mode onlydark: Force dark mode onlydisable: Disable dark mode support (uses light colors only)
Typography in Dark Mode:
You can also specify different colors for dark mode in the typography system:
[theme.typography.header]
color = "#000000" # Light mode color
color_dark = "#ffffff" # Dark mode colorThe [meta] section configures page metadata and extras:
[meta]
title = "My Links" # Page title (appears in browser tab)
description = "All my links" # Page description (for SEO)
favicon = "https://example.com/favicon.ico" # Optional favicon (URL or local path)
custom_css = "" # Optional custom CSS
analytics = "" # Optional analytics code
show_footer = false # Hide "Made with Genkan" footer (default: true)- URL:
favicon = "https://example.com/favicon.ico" - Local file:
favicon = "./images/favicon.png"(relative to config.toml) - Supported formats: .ico, .png, .jpg, .svg, .gif, .webp
- Local files are automatically embedded as base64 data URLs
[meta]
custom_css = """
.link-button:hover {
background: linear-gradient(90deg, #667eea, #764ba2);
color: white;
}
"""[meta]
analytics = """
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
</script>
"""The [image] section controls automatic image compression and resizing for faster page loads:
[image]
avatar_size = 512 # Target size for profile avatars (default: 512px)
social_icon_size = 128 # Target size for social link icons (default: 128px)
link_icon_size = 128 # Target size for link icons (default: 128px)
favicon_size = 64 # Target size for favicon (default: 64px)- Automatic Download: All external image URLs are downloaded during generation
- Smart Resizing: Images are resized to target dimensions while maintaining aspect ratio
- High-Quality Compression: Uses Lanczos3 filter for excellent visual quality
- Base64 Embedding: All images are embedded as base64 data URLs in the HTML
- Self-Contained Output: The generated HTML file has no external dependencies
- SVG images: Never resized to preserve vector quality
- ICO favicons: Not resized (kept as-is for compatibility)
- Small images: If already smaller than target size, kept at original dimensions
- Emojis: Text emojis (π, π§, etc.) are passed through without processing
Real-world example from testing:
- X logo icon: Reduced from 98KB to 6.5KB (93% reduction!)
- Bluesky logo: Reduced from 41KB to 8KB (81% reduction)
- Misskey icon: Reduced from 23KB to 9KB (60% reduction)
The compression happens automatically during the build process, with progress logged to the console.
- For profile avatars: 512px provides excellent quality for displays
- For link icons: 128px is optimal for link button icons
- For social icons: 128px works well for small social media icons
- For favicons: 64px is standard for modern favicons
- Adjust sizes based on your design needs - larger values = better quality but bigger file size
Add as many links as you want using [[links]]:
[[links]]
title = "My Website" # Link title (required)
url = "https://example.com" # Link URL (optional - omit for non-clickable)
icon = "π" # Icon (optional - omit for text-only)
description = "Check out my site" # Subtitle (optional)
link_type = "block" # Type: "block" or "space" (default: "block")
height = "40px" # Height for spacers (only for link_type = "space")Block Type (default):
- Standard clickable or non-clickable link box
- Omit
urlto make it non-clickable (displays as text box) - Omit
iconfor text-only display (no icon shown)
# Standard clickable link
[[links]]
title = "My Website"
url = "https://example.com"
icon = "π"
link_type = "block"
# Non-clickable text block (no URL)
[[links]]
title = "Important Notice"
description = "This is just informational text"
link_type = "block"
# Text-only clickable link (no icon)
[[links]]
title = "Simple Link"
url = "https://example.com"
link_type = "block"Space Type:
- Creates vertical spacing between links
- Use
heightto control the space (e.g., "20px", "40px")
[[links]]
title = ""
link_type = "space"
height = "30px"-
Emoji: Use any emoji
icon = "π" icon = "πΌ" icon = "π§"
-
Image URL: Use an icon from the web
icon = "https://cdn.simpleicons.org/github/000000" icon = "https://example.com/my-icon.png"
-
No icon: Omit the icon field for a default link icon
[[links]] title = "My Link" url = "https://example.com" # No icon specified - will show default π
- Simple Icons:
https://cdn.simpleicons.org/[brand]/[color]- GitHub:
https://cdn.simpleicons.org/github/000000 - Twitter:
https://cdn.simpleicons.org/twitter/1DA1F2 - LinkedIn:
https://cdn.simpleicons.org/linkedin/0A66C2
- GitHub:
Here's a complete configuration example:
[profile]
name = "Jane Doe"
bio = "Designer, Developer & Creator β¨"
avatar = "https://avatars.githubusercontent.com/u/123456"
background = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
[theme]
name = "simple"
primary_color = "#667eea"
secondary_color = "#2d3748"
background_color = "#ffffff"
button_style = "pill"
font_family = "Inter, system-ui, sans-serif"
[meta]
title = "Jane Doe | Links"
description = "All my important links in one place"
favicon = "https://example.com/favicon.ico"
[image]
avatar_size = 512
social_icon_size = 128
link_icon_size = 128
favicon_size = 64
[[links]]
title = "Portfolio"
url = "https://janedoe.com"
icon = "π¨"
description = "View my work and projects"
[[links]]
title = "GitHub"
url = "https://github.com/janedoe"
icon = "https://cdn.simpleicons.org/github/000000"
[[links]]
title = "Twitter"
url = "https://twitter.com/janedoe"
icon = "https://cdn.simpleicons.org/twitter/1DA1F2"
[[links]]
title = "Email"
url = "mailto:hello@janedoe.com"
icon = "βοΈ"
description = "Get in touch"Generate your site from the configuration:
genkan build # Use default config.toml
genkan build -c custom.toml # Use custom config file
genkan build -o dist # Output to custom directoryInitialize a new project:
genkan init # Initialize in current directory
genkan init my-project # Initialize in new directoryValidate your configuration without building:
genkan validate # Validate config.toml
genkan validate -c custom.toml # Validate custom configEvery generated page includes a share button (top right corner) that allows visitors to:
- Generate QR Code: Automatically creates a QR code for the current page URL
- Copy Link: Quick copy-to-clipboard functionality
- Mobile Friendly: Works seamlessly on desktop and mobile devices
The share button appears as a floating button in the top-right corner and opens a modal with:
- A scannable QR code (great for sharing in person)
- The page URL in a text field
- A copy button for quick clipboard access
No configuration needed - it works out of the box on every generated page!
Control whether to show the "Made with Genkan" footer:
[meta]
show_footer = false # Hide the footer (default: true)Use custom background images for your page:
[profile]
# Option 1: Use a gradient or solid color
background = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
# Option 2: Use a background image (takes priority)
background_image = "https://example.com/background.jpg"Background images are automatically set to:
- Cover the entire viewport
- Stay fixed during scrolling
- Center positioned
- No repeat
Since Genkan generates static HTML, you can deploy anywhere:
# Generate your site
genkan build -o docs
# Commit and push
git add docs/
git commit -m "Update link page"
git push
# Enable GitHub Pages in repository settings (source: docs folder)# Generate your site
genkan build
# Drag and drop the output folder to Netlify
# Or connect your Git repository# Install Vercel CLI
npm i -g vercel
# Deploy
genkan build
cd output
vercelSimply upload the contents of the output/ directory to your web server via FTP/SFTP.
Genkan supports custom themes! Each theme consists of three files:
themes/
βββ my-theme/
βββ template.html # HTML structure with placeholders
βββ style.css # Styles (supports template variables)
βββ script.js # Optional JavaScript
template.html supports these Tera template variables:
{{ profile.name }} <!-- Profile name -->
{{ profile.bio }} <!-- Profile bio -->
{{ profile.avatar }} <!-- Avatar URL -->
{{ profile.background }} <!-- Background style -->
{{ theme.primary_color }} <!-- Primary color -->
{{ theme.text_color }} <!-- Text color -->
{{ theme.button_style }} <!-- Button style -->
{{ meta.title }} <!-- Page title -->
{{ meta.description }} <!-- Page description -->
{% for link in links %}
{{ link.title }} <!-- Link title -->
{{ link.url }} <!-- Link URL -->
{{ link.icon }} <!-- Link icon -->
{{ link.description }} <!-- Link description -->
{% endfor %}style.css supports template variables too:
:root {
--primary-color: {{ theme.primary_color }};
--text-color: {{ theme.text_color }};
}See themes/simple/ for a complete example.
Make sure your theme exists in the themes/ directory:
themes/
βββ simple/ # Theme name must match config
βββ template.html
βββ style.css
βββ script.js
Check your config.toml syntax:
- Strings must be in quotes:
title = "My Link" - Each
[[links]]section must havetitleandurl - Colors must be valid CSS:
#000000orrgb(0,0,0)
Make sure URLs include the protocol:
- β
url = "https://example.com" - β
url = "example.com"
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details
- Inspired by Linktree and similar services
- Built with Rust, Tera, and modern web standards
- Name inspired by Japanese architecture (genkan = entrance)
Made with β€οΈ using Genkan