WebKit is a hybrid Markdown + HTML site engine written in C#.
It transforms simple .md
pages into clean, responsive websites — with built-in layouts, dark/light mode, and expression support.
- Responsive layout 📱
- Dark 🌙 + Light ☀️ mode
- Hybrid Markdown + HTML syntax
- Simple expressions with Getters + Setters
- Configurable via
webkit.json
dotnet tool install -g Boson.WebKit
webkit init -n MySite
cd MySite
webkit build
webkit serve
Open http://localhost:3000 🎉
webkit.json
{
"Properties": {
"Name": "MySite",
"Author": "CodingBoson"
}
}
Access with expressions:
# Welcome to {{ .Name }} by {{ .Author }}
MySite/
├─ build/ # Generated output
├─ Resources/ # All resources live here
│ ├─ Pages/ # Markdown + hybrid HTML pages
│ ├─ Shared/ # Reusable components
│ ├─ Static/ # CSS, JS, images
│ └─ Layout.html # Global layout
├─ .gitignore
├─ README.md
└─ webkit.json # Site config
webkit init <Name> # Create new site
webkit build # Build static site
webkit serve # Run local dev server
webkit clean # Clear build output
The Layout.html
in Resources/
defines the global wrapper for your pages.
Every page gets rendered inside this layout.
Example:
<!DOCTYPE html>
<html>
<head>
<title>{{ .Title }}</title>
<link rel="stylesheet" href="/webkit.css">
</head>
<body>
{{ .NavBar }}
<main>
{{ .Content }}
</main>
<footer>
<p>© {{ .Name }} by {{ .Author }}</p>
</footer>
</body>
</html>
In WebKit, shared components are just resources inside Resources/Shared/
.
To use them:
- Create a file in
Resources/Shared/
(e.g.NavBar.html
) - Reference it in
webkit.json
- Use it as a property in any page or layout
Resources/Shared/NavBar.html
<nav>
<a href="/">Home</a>
<a href="/About.html">About</a>
</nav>
webkit.json
{
"Properties": {
"Name": "MySite",
"Author": "CodingBoson",
// First, define a property in the `webkit.json` that references the shared HTML/markdown file. "NavBar": "@Shared/NavBar.html"
"NavBar": "@Shared/NavBar.html"
}
}
Layout.html
<body>
{{ .NavBar }}
<main>{{ .Content }}</main>
</body>
- No new syntax → Components are just properties.
- No hidden magic → WebKit doesn’t treat
Shared/
specially. It’s just a folder convention. - Uniform API → Whether you use
.Name
,.Author
, or.NavBar
, it’s the same expression system.
This makes WebKit:
- Predictable → All resources behave the same
- Simple → No separate “component language”
- Composable → You can nest and reuse shared parts freely
# Expressions
WebKit supports **expressions** inside Markdown and HTML.
They are written with double curly braces:
```markdown
{{ .Property }}
A Getter inserts the value of a property.
Example:
Welcome to {{ .Name }} by {{ .Author }}
With this config:
{
"Properties": {
"Name": "MySite",
"Author": "CodingBoson"
}
}
Result:
Welcome to MySite by CodingBoson
Properties in webkit.json
can point to other resources, like files in Resources/Shared/
.
{
"Properties": {
"NavBar": "@Shared/NavBar.html"
}
}
Now you can use:
{{ .NavBar }}
WebKit will inline the content of Resources/Shared/NavBar.html
.
A SetterExpression allows you to define or override a property inside a page.
Syntax:
{{ .Property = value }}
Example:
{{ .Title = .Name Home }}
# Welcome to {{ .Name }}
Here:
.Title
is set to"MySite Home"
- It can be used later in
Layout.html
(e.g., inside<title>
)
Setters can concatenate multiple values:
{{ .Title = .Name " - " .Author }}
With:
{
"Properties": {
"Name": "MySite",
"Author": "CodingBoson"
}
}
Result:
<title>MySite - CodingBoson</title>
When WebKit resolves an expression:
- Check runtime Setters (defined in the current page)
- Check
webkit.json
Properties - If value is a resource reference (e.g.,
@Shared/...
), load its content - Fallback → leave the expression untouched
This makes expressions predictable:
- Pages can override defaults (via Setters)
- Layouts and Shared resources stay flexible
To write an expression literally (without evaluating it), escape with \\
:
\\{{ .Author }}
Result:
{{ .Author }}
Expressions are the glue of WebKit:
- Getters → read values
- Setters → define or override values
- References → pull in resources
- All unified under one minimal syntax
👉 No custom DSL. 👉 No templates-within-templates. 👉 Just properties + resources, flowing through the build pipeline.
GPL-3.0 © BosonWare Technologies