# bim
A content-first, convention-over-configuration static site generator written in Rust.
Designed to support blogs, digital gardens, code snippets, recipes, talks, and slides in a single coherent knowledge base.
## Philosophy
- **Markdown** as the primary authoring format
- **Filesystem structure** as the source of truth
- **No front matter** - metadata extracted from filenames and git
- **Lenient behavior** - warnings instead of hard errors
- **Fast** - parallel processing with Rayon
## Installation
```bash
cargo install bim
```
Or build from source:
```bash
cargo build --release
./target/release/bim --help
```
## Quick Start
```bash
# Create a new site
mkdir my-site && cd my-site
# Create some content
mkdir blog
echo "# Hello World" > blog/2024-01-15-hello-world.md
echo "# About" > index.md
# Build the site
bim build
# Serve locally with live reload
bim serve --watch
```
## CLI Commands
### `bim build`
Build the static site.
```bash
bim build # Build to ./dist
bim build --output public # Build to ./public
bim build --drafts # Include draft content
bim build --clean # Clean output directory first
```
### `bim serve`
Build and serve the site locally.
```bash
bim serve # Serve on http://127.0.0.1:3000
bim serve --port 8080 # Custom port
bim serve --host 0.0.0.0 # Bind to all interfaces
bim serve --watch # Watch for changes and rebuild
bim serve --drafts # Include draft content
```
### `bim watch`
Watch for changes and rebuild.
```bash
bim watch # Watch and rebuild to ./dist
bim watch --drafts # Include draft content
```
### `bim prep-images`
Process images without building the full site.
```bash
bim prep-images # Process images
bim prep-images --force # Force reprocessing all images
```
## Directory Structure
```
my-site/
├── index.md # Homepage
├── nav.md # Navigation menu
├── blog/ # Blog posts (date-sorted, RSS feed)
│ ├── 2024-01-15-hello.md
│ └── 2024-02-01-update.md
├── notes/ # Hierarchical notes (auto-indexes)
│ ├── getting-started/
│ │ ├── index.md
│ │ └── installation.md
│ └── features/
│ └── backlinks.md
├── snippets/ # Code snippets (syntax highlighted)
│ ├── rust/
│ │ └── error_handling.rs
│ └── python/
│ └── decorators.py
├── talks/ # Conference talks
├── projects/ # Project pages
├── recipes/ # Recipes or tutorials
├── slides/ # Presentation slides
├── tags/ # Custom tag pages (optional)
│ └── rust.md
├── contexts/ # Custom context pages (optional)
│ └── linux.md
├── layouts/ # Custom HTML layouts
│ └── default.html
├── static/ # Static files (copied as-is)
│ ├── css/
│ └── robots.txt
└── images/ # Images (processed/optimized)
└── hero.jpg
```
## Collections
| blog | /blog/ | Date-sorted, RSS feed, flat structure |
| notes | /notes/ | Hierarchical, auto-indexes for directories |
| snippets | /snippets/ | Syntax highlighting, language detection |
| talks | /talks/ | Flat structure |
| projects | /projects/ | Flat structure |
| recipes | /recipes/ | Flat structure |
| slides | /slides/ | Flat structure, no backlinks |
| tags | /tags/ | Auto-generated from content |
| contexts | /contexts/ | Auto-generated from content |
## Content Features
### Dates from Filenames
Prefix filenames with `YYYY-MM-DD-` to set the date:
```
blog/2024-01-15-my-post.md → /blog/my-post/
```
If no date prefix, the git commit date is used.
### Titles from Headings
The first `# Heading` in your markdown becomes the page title:
```markdown
# My Awesome Post
Content here...
```
### Drafts
Files starting with `_` or in `_drafts/` directories are drafts:
```
blog/_work-in-progress.md # Draft (underscore prefix)
blog/_drafts/ideas.md # Draft (in _drafts directory)
```
Include drafts with `--drafts` flag.
### Tags
Use `[#tag name]` syntax to tag content:
```markdown
This post is about [#rust] and [#web development].
```
Tags are automatically converted to links and aggregated at `/tags/`.
### Contexts
Use `[@context name]` syntax to specify contexts:
```markdown
This applies to [@linux] and [@docker] environments.
```
Contexts are automatically converted to links and aggregated at `/contexts/`.
### Backlinks
Internal links are tracked and backlinks are displayed automatically. Link to other pages:
```markdown
See also [my other post](/blog/other-post/).
```
The linked page will show a backlink to this page.
### Directives
Use directives to embed dynamic content:
```markdown
## Recent Posts
{{recent blog 5}}
## Latest Notes
{{recent notes 3}}
```
Available directives:
- `{{recent collection count}}` - List recent items from a collection
## Navigation
Create `nav.md` to define the site navigation:
```markdown
- [Home](/)
- [Blog](/blog/)
- [Notes](/notes/)
- [Snippets](/snippets/)
```
## Layouts
Create custom layouts in the `layouts/` directory. Layouts are HTML files with placeholders:
```html
<!DOCTYPE html>
<html lang="{{lang}}" dir="{{dir}}">
<head>
<title>{{title}}</title>
</head>
<body>
{{nav}}
<main>{{content}}</main>
{{backlinks}}
<footer>Last modified: {{last_modified}}</footer>
</body>
</html>
```
### Available Placeholders
| `{{title}}` | Page title |
| `{{content}}` | Rendered HTML content |
| `{{nav}}` | Navigation HTML |
| `{{backlinks}}` | Backlinks section HTML |
| `{{last_modified}}` | Last modification date |
| `{{lang}}` | Content language (e.g., "en", "ar") |
| `{{dir}}` | Text direction ("ltr" or "rtl") |
### Layout Selection
Layouts are selected by collection:
- `layouts/blog.html` - Blog posts
- `layouts/notes.html` - Notes
- `layouts/snippets.html` - Code snippets
- `layouts/slides.html` - Slides
- `layouts/default.html` - Fallback for all collections
## Code Snippets
Place code files in `snippets/` to create syntax-highlighted pages:
```
snippets/
├── rust/
│ └── error_handling.rs
├── python/
│ └── decorators.py
└── bash/
└── git_aliases.sh
```
Each file becomes a page with:
- Title from filename
- Syntax highlighting
- Backlink support
## Language Detection
Content language is automatically detected:
- English content: `lang="en"` `dir="ltr"`
- Arabic content: `lang="ar"` `dir="rtl"`
- Other RTL languages supported
## RSS Feed
An RSS feed is automatically generated at `/feed.xml` for the blog collection.
## Sitemap
A sitemap is automatically generated at `/sitemap.xml` with all pages.
## Image Processing
Images in the `images/` directory are:
- Copied to output
- Optimized for web (future: resize, compress)
## Static Files
Files in `static/` are copied as-is to the output:
```
static/css/custom.css → dist/css/custom.css
static/robots.txt → dist/robots.txt
```
## Git Integration
If your site is in a git repository:
- File modification dates come from git history
- Uncommitted files use current time
## Dark Mode
The default layout includes automatic dark mode support using `prefers-color-scheme` media query.
## Example Site
See [bim.gumx.cc](https://bim.gumx.cc) for a complete example site demonstrating all features.
## Using as a Library
bim can also be used as a library in your Rust projects:
```rust
use bim::{config::Config, discovery, render};
fn main() -> anyhow::Result<()> {
let config = Config::default();
let site = discovery::discover_site(&config)?;
render::build_site(&site, &config)?;
Ok(())
}
```
## Environment Variables
- `RUST_LOG=bim=info` - Enable info logging
- `RUST_LOG=bim=debug` - Enable debug logging
## Links
- Repository: https://git.sr.ht/~gumx/bim
- Website: https://bim.gumx.cc
## License
MIT