Tips
Navigation behavior
- Files and folders are sorted alphabetically and intermixed by default; use
_order.txtto override index.mdin any folder is hidden — it IS that folder's home page- Empty directories are hidden from the nav tree
- The active page is highlighted in the nav
Serving from a subdirectory
OwnShip auto-detects its base path. Drop it into /docs/ or /notes/ and everything — nav links, home URL, {{home}} tokens, image paths — works correctly without any configuration.
Image paths
Images referenced in .md files are served root-relative, so they display correctly regardless of which page you're viewing. Use paths relative to your content root:

Running the guide locally
This guide is served by OwnShip. To run it locally, drop index.php into this guide/ folder and run OwnShipPreview.bat or OwnShipPreview.sh, or any local PHP server, from that directory.
Quick _theme.css recipes
These drop straight into _theme.css and can be combined freely.
Font size
Scale the content area only:
main { font-size: 1.125rem; } /* roomier — ~18px at default base */
main { font-size: 0.9375rem; } /* compact — ~15px */
To scale everything including the nav, shift the rem baseline instead:
html { font-size: 18px; }
Font family
OwnShip defaults to system-ui, sans-serif — the native UI font on each platform. To override, target body for global, main for content only, or code, pre for monospace:
/* serif body — readable for long-form content */
body { font-family: Georgia, 'Times New Roman', serif; }
/* content area only — keeps nav in system-ui */
main { font-family: Georgia, 'Times New Roman', serif; }
/* monospace style for code blocks */
code, pre { font-family: 'Courier New', Courier, monospace; }
Using a web font. There are three routes, and which one suits you is a judgement call rather than a rule. All of them end the same way — a font-family in _theme.css:
body { font-family: 'Lora', Georgia, serif; }
What differs is where the font comes from.
1. A font CDN — the quickest route. Load it in _header.md or _theme.js with a <link> tag:
<!-- Bunny Fonts — EU-hosted, no logging, no cookies -->
<link rel="stylesheet" href="https://fonts.bunny.net/css?family=lora:400,400i,700&display=swap">
<!-- Google Fonts — the same typefaces, the bigger catalogue -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,700;1,400&display=swap">
One line either way, no download, nothing to maintain. The cost is the same for both: the font is fetched from someone else's server on every page load, so your readers' addresses reach that service, and your site's appearance depends on it staying up.
We suggest Bunny. It serves the same open typefaces from the EU, keeps no logs and sets no cookies, so it makes the disclosure about as small as a third-party font request can be — which matters more if you have EU readers. It is a drop-in swap: change the hostname and the family syntax and nothing else. The honest counterweight is longevity. Google Fonts will still be there in ten years; Bunny is a smaller operation, and if it ever changed terms your site would lose its typeface until you edited one line. Google also has the larger catalogue, so some families are only available there.
Neither is wrong. Pick the one whose trade you prefer, and note that it is one line in one file if you change your mind.
A note if you are writing a drop-in theme. Put the @import inside your _theme-NAME.css rather than using a <link>, and OwnShip will hold the request back until a visitor actually selects your theme. Someone who installs your theme but never switches to it contacts nobody. A <link> in _header.md cannot get that treatment, because it applies to every page regardless of theme.
And when a reader does pick it, it is their own browser that fetches the font — once — not your server. The browser then caches it for weeks, so it is not fetched again on every page. In plain terms: a reader who uses your theme reaches the font service once; after that it loads from their browser cache, and everyone else — and every other theme — reaches nobody.
2. Host the font yourself — nothing leaves your server. Most fonts on Google Fonts and Bunny are published under the SIL Open Font License, which expressly permits you to download and serve your own copy. Put the file in a _-prefixed folder so it stays out of your navigation, keep the font's licence file beside it (the OFL asks that the licence travel with the font), and point at it directly:
@font-face {
font-family: 'Lora';
src: url('_fonts/lora-regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
}
body { font-family: 'Lora', Georgia, serif; }
No <link> tag is needed for this version — nothing is fetched from anywhere but your own server, and the font still downloads only when a page actually needs it. Use .woff2; every browser of the last decade supports it, and it's the smallest format.
One practical snag worth knowing before you start: Google's own Download family button gives you a zip of .ttf files, not the .woff2 you want. google-webfonts-helper is the usual way round it — pick a family, choose the weights, and it hands you the .woff2 files together with a ready-made @font-face block. Nothing to install.
3. Embed the font in the CSS itself — one file, works offline. The same @font-face block as above, but with the font written directly into the stylesheet as a data: URI instead of pointing at a file:
@font-face {
font-family: 'Lora';
src: url('data:font/woff2;base64,d09GMgABAAAAA…') format('woff2');
font-weight: 400;
font-display: swap;
}
That makes the theme a single self-contained file with nothing beside it to lose, which is the right form for one you hand to someone else. It costs bytes — the font travels with the stylesheet whether or not a page uses it — so it suits a subset of one weight rather than a family of six. Keep the licence text in a comment at the top of the file, since there is no longer a separate licence file sitting next to the font.
Page transitions
Each nav click is a full page reload, so a CSS animation on main fires naturally on every page change. Add one via _theme.css:
main { animation: hv-fade .3s ease; }
@keyframes hv-fade {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
Other ideas: translateX(-8px) slides in from the left; scale(.98) gives a subtle zoom-in feel.
Suppress the sidebar
For small sites — business cards, microsites, short link lists — set nav_style = none in _site.ini. OwnShip removes the nav pane entirely and expands the content area to fill the full width. If content_width is also set, the header padding is adjusted automatically so header text aligns with your content.
Handle navigation in a _header.md instead:
# [My Site]({{home}})
[home](index.md) · [about](about.md) · [contact](contact.md)
Center the header text — add to _theme.css:
.header-md { flex: 1; }
header h1, header p { text-align: center; }
Image captions
Markdown has no caption syntax. The simplest approach is a <p> with a .caption class immediately below the image:

<p class="caption">E-MU E-Synth · 1998</p>
Add the styling to _theme.css:
.caption { font-size: 0.833rem; font-style: italic; text-align: center; }
Keyboard navigation indicator
When keyboard navigation is active, OwnShip marks the focused nav item with a thin accent bar. On minimal sites — business cards, microsites — you may prefer to suppress it:
nav li.kb-selected > a { border-left: none; padding-left: .5rem; }
Keyboard navigation still works; only the visual indicator is removed.
Dogfooding
The guide you're reading at ownship.cc/guide/ is itself served by OwnShip — the same index.php you downloaded. The main ownship.cc site is a separate static page.