For developers
An appendix for self-builders: Quiet's build commands, stack, file map, the checks that gate a release, the translation workflow, and the stable hook contract.
Most site editors will never need anything here. This page is for developers who want to build the theme from source, add a language, or extend it in a fork.
You do not need any of this to use Quiet
The theme you downloaded is already built. Upload the zip and it works. Everything below is about working on the source.
Build requirements
| Node.js | 22.12.0 or later |
| Yarn | 1.x |
| Ghost | 6.0.0 or later, for a local preview |
Stack
- Vite for the asset build.
- Tailwind CSS v4, configured entirely in CSS. There is no
tailwind.config.js. - Vanilla ES modules. No framework, no jQuery, no Alpine.
- Handlebars templates, as Ghost requires.
- Two vendored or bundled front-end pieces: a YouTube facade, a patched Vimeo facade that requests do-not-track, Media Chrome for uploaded video, and PhotoSwipe for the photo viewer.
Build commands
yarn install # install dependencies
yarn dev # Vite in watch mode, for use alongside a local Ghost
yarn build # production assets into assets/built/
yarn lint # translation parity, contrast sweep, gscan
yarn vitest # the unit and DOM tests
yarn test # lint plus vitest
yarn zip # test, build, and package quiet.zipThe checks that gate a release
yarn lint runs three gates, all of which have to pass:
- Translation parity (
scripts/check-i18n.mjs). Fails if a template uses a string that is not inlocales/en.json, ifen.jsondeclares a string no template uses, or if any of the other seventeen locale files is missing a key or holds an empty value. - Contrast (
scripts/check-contrast.mjs). Scores every text colour against the surfaces its own mode puts behind it, in light and dark, and fails on anything below the threshold. - gscan, Ghost's own theme validator. Zero errors and zero warnings.
yarn vitest runs 26 test files covering the JavaScript modules, most of them DOM tests against real markup.
assets/built is committed
There is no build step in CI, so whatever is committed under assets/built/ is what a site serves. After any CSS or JavaScript change, run yarn build and commit the result along with the source.
File map
Templates
Sixteen at the root:
| File | Serves |
|---|---|
default.hbs | The shared layout for every template except private |
home.hbs | The homepage |
index.hbs | The article archive |
post.hbs | A post, including episodes and films |
page.hbs | A page, including projects and homepage section pages viewed directly |
tag.hbs, author.hbs | Ghost's tag and author archives |
podcast.hbs, videos.hbs | The two collection routes. Not custom templates: they need posts and pagination |
custom-contact.hbs, custom-gallery.hbs, custom-newsletter.hbs, custom-projects.hbs | The four templates in the editor's dropdown |
error.hbs, error-404.hbs | Errors |
private.hbs | The door on a password-protected site. Standalone, with inlined CSS, because Ghost blocks theme assets before authentication |
Directories
| Path | Holds |
|---|---|
partials/home/ | The homepage dispatcher and the ten bands, plus the introduction's three layouts |
partials/post/ | Feature image, byline, gate teaser, share row, author card, post navigation, related posts |
partials/video/, partials/podcast/, partials/project/ | The cards and heroes for those three content types |
partials/icons/ | Inline SVG icons |
assets/css/ | index.css (design tokens and base), plus components, prose, koenig, players |
assets/js/ | One module per feature, each with its tests beside it |
assets/js/quiet-core/ | The soft-navigation router, the re-init lifecycle, the progress bar, active-nav |
assets/js/media/ | The video player: stage, sources, controls, artwork |
locales/ | The translation files, en.json first among them |
routes.yaml | The optional routing file |
Adding a language
No build needed
Translation files are plain JSON and are read at runtime, so adding one does not require a build.
- Copy
locales/en.jsontolocales/<code>.json. - Translate the values, leaving the keys and any placeholders (
{name},%number%) alone. - Set Settings → General → Publication language to that code.
- Run
yarn lintto confirm parity.
Quiet is a left-to-right theme in this release; right-to-left languages are not supported until they have been tested in a future version.
The hook contract
Quiet exposes four attributes as a public styling API: data-region, data-component, data-variant and data-part. The rules, if you are extending the theme:
- Additive only. Renaming or removing a handle is a breaking change and belongs in the changelog.
- Do not hook a load-bearing element. Anything a script measures or rebuilds (the menu list, the player host, the photo rails, the masonry walls) gets a wrapper for styling instead.
- Reserved prefixes:
data-mp-,data-nav-,data-quiet-,data-gallery-,data-copy-anddata-footer-navare the theme's own machinery;data-portal,data-members-anddata-ghost-belong to Ghost. Two of Quiet's own are authored by customers in code injection (data-quiet-social-links,data-quiet-podcast-links,data-quiet-videos-linksand their meta-tag names), so renaming them breaks live sites silently. - Every new handle is documented in the hook reference.
Source and licence
The theme is distributed as a zip with the source in it: templates, CSS, JavaScript and locales are all readable and editable. The licence covers what you may do with it, and is in LICENSE.md inside the zip.