Citadel
Data in. HTML out. Nothing else.
Pipeline
Four stages. One direction.
Define
Pages are enum variants. Routes are types. If a page doesn't exist in your enum, it doesn't compile.
Construct
Plain functions receive site + page, build HTML. No lifecycle hooks. No inheritance. Just functions.
Decree
Global find-and-replace across every page. CSS variables, year stamps, site-wide tokens. Decreed once, applied everywhere.
Write
Static HTML files. Sitemap. Robots. RSS. Optimised images. Written to disk. Deployed anywhere.
The Problem
Every SSG is the same problem wearing a different hat
Template Archaeology
Your page is a template that extends a layout that includes a partial that references a config that pulls from a data file. You need five files open to understand one page.
Plugin Roulette
Need sitemap generation? Install a plugin. Need image optimisation? Another plugin. Need SEO meta tags? Another. Each with its own config format, its own bugs, its own abandonment timeline.
Framework Theatre
You learn the framework's opinions; its routing conventions, its build hooks, its special directories. Then the framework updates. Your site breaks. You archaeology again.
AI-Hostile
An AI working with your site needs to reconstruct your mental model from fragments scattered across dozens of files. Templates here, config there, logic somewhere else. No single file tells the whole story.
The Answer
What if a page was just a function?
Citadel is a Rust library. Your pages are data. Your constructors are plain functions. CSS is declared alongside HTML in the same function scope. There are no templates, no themes, no plugins, no config files, no magic directories.
One file. One function. One page. The entire mental model fits in a single scroll.
An AI reads one function and understands the entire page: the HTML, the CSS, the routing, the SEO. That's not a feature. That's the architecture.
AI-Native
Built for the context window
- ✗ Template file
- ✗ Layout file
- ✗ Partial files (3-5)
- ✗ Config file
- ✗ CSS file(s)
- ✗ Plugin configs
- ✗ Data files
7-12 files to understand one page
- ✓ Constructor function
1 file. Everything.
When an AI builds with Citadel, it sees the whole page in a single function. No context chasing. No framework archaeology. No guessing where the CSS lives. We built it because AI needed an SSG it could actually use.
In Practice
Real code from this site
pub enum WIPages {
Homepage,
Services,
Contact,
Product(ProductId),
BlogHub,
InsightsList,
InsightsPost(PostData<WIFrontmatter>),
EmergenceList,
EmergencePost(PostData<WIFrontmatter>),
CaseStudies,
}
pub fn construct_homepage(
site: &mut Site<WIPages, ()>,
page: &mut Page<WIPages>,
) {
let head = site.construct_head(page);
css(site);
page.foundation.content = Some(format!(r##"
<!DOCTYPE html>
<html lang="en">
{head}
<body>
<main class="homepage">
...
</main>
</body>
</html>
"##));
}
site = site
.add_constructor(Homepage, construct_homepage)
.add_constructor(Services, construct_services)
.add_constructor(Product(Citadel), construct_citadel)
.add_head_constructor()
.add_pages(pages);
site.commence();
site.declare_css("homepage", r##"
main.homepage {
.hero {
min-height: 100vh;
display: flex;
align-items: center;
}
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
"##);
Declaration System
Declare everything. Configure nothing.
CSS declared with a semantic key. Idempotent. Declare the same key from anywhere, it's only included once. Automatic priority ordering: foundation → typography → components.
Global find-and-replace across every page. 2026 becomes 2026. Wilderness Interactive becomes your title. Works in HTML and CSS. Decreed once, applied everywhere.
Inject content at eight strategic positions: Fonts, Schemas, HeadTop, HeadBottom, BodyTop, BodyBottom, Analytics, Scripts. Site-wide, automatic, ordered.
Generates the entire <head> tag from page data. Title, meta description, Open Graph, Twitter Cards, canonical URL, CSS bundle, fonts, schemas. All from your PageFoundation.
Capabilities
Everything you need. Nothing you don't.
Type-Safe Routing
Pages are enum variants. Routes derived from types. If a page variant doesn't exist, your code doesn't compile. Discriminant matching handles dynamic content types: blog posts, products, categories. All through the same type system.
Automatic SEO
Sitemap generation, robots.txt, Open Graph tags, Twitter Cards, canonical URLs, meta descriptions, JSON-LD schemas. All generated from your page data. No plugins. No config files. Just data in, SEO out.
CSS Priority System
Foundation styles load first. Typography second. Page-specific CSS alphabetically after. Declare CSS from any function in any file. Citadel orders it correctly. No specificity wars. No !important hacks.
Content System
Generic frontmatter parsing with full markdown rendering. Define your own frontmatter struct, point at a directory, and Citadel parses, sorts, and hands you typed data. Posts, products, docs. Any content model you need.
Eight Placements
Fonts, schemas, head-top, head-bottom, body-top, body-bottom, analytics, scripts. Inject content at exactly the right position in the document. Site-wide. Automatic. No guessing.
Zero Runtime
Compiles to a native binary. Generates pure static HTML and CSS. No JavaScript framework shipped. No hydration step. No client-side routing. Pages load as fast as the network can deliver them.
Intelligent Assets
Images are automatically optimised, converted to modern formats, and served with correct dimensions. Responsive srcsets generated from a single source image. No manual resizing.
No Config Files
No YAML. No TOML. No JSON config. No special directories. Your site is a Rust program. Configuration is code. Type-checked, refactorable, version-controlled.
You're looking at it.
This entire site, every page, every blog post, every product page you're reading,
is built on Citadel. So are the client sites serving over 30,000 monthly visitors.
The CSS was declared with declare_css.
The head was built with construct_head. The sitemap was
generated automatically. Content drops in as markdown, compiles, and deploys.
We don't sell a vision. We ship on it.
Performance
What zero runtime actually means
Time to Interactive. There's no JavaScript to parse, no framework to boot, no hydration step. The page is interactive the moment HTML arrives.
Total page weight for a typical page. HTML + CSS. No framework bundle. No polyfills. No tree-shaking because there's nothing to shake.
Full site build time. Native Rust binary. 22 pages, multiple content types, image optimisation, sitemap generation. Faster than your framework's dev server starts.
License
Sovereign software.
Citadel is available under the Citadel License. Build with it. Sell what you build. The tool itself remains sovereign. Because the things that matter shouldn't be owned by committees.
Get in Touch