For developers
A short appendix for self-builders — Signal's build commands, tech stack, file map, the i18n workflow, and the stable data-* hook contract.
This page is the short reference for developers customizing Signal from source. Most site editors won't need anything here — uploading the pre-built signal.zip is enough. If you want to fork the theme, change styles at the source level, or rebuild after edits, read on.
Custom code is overwritten on theme update
If you modify theme files directly and then upload an updated signal.zip through Ghost Admin, your changes are erased. Fork the repo, commit your changes to your fork, and rebuild your own zip — don't edit files in place on a production install. For small CSS or JavaScript tweaks, prefer Ghost's Settings → Code injection, which survives theme updates — see Code injection for the stable selectors Signal exposes for exactly this.
Build requirements
- Node.js v22.12.0 or later
- Yarn (v1.x)
- Ghost v6.0.0 or later for the running site that will host the built theme
Tech stack
Signal is built with Vite (bundling), Tailwind CSS v4 (styling, with the typography plugin for episode content), and vanilla JavaScript (no framework) for interactivity — the persistent player, transcripts, chapters, navigation, and Library. Media playback uses Media Chrome for uploaded video and lite-youtube / lite-vimeo facades for embeds. Templates are standard Ghost Handlebars.
Build commands
All commands run from the theme root.
| Command | What it does |
|---|---|
yarn install | Install dependencies. |
yarn dev | Vite dev server with HMR. Useful when iterating on CSS or JS in a local Ghost install pointed at the theme directory. |
yarn build | Production build to assets/built/. |
yarn lint | Runs lint:i18n (translation-parity check) then lint:theme (GScan compliance against Ghost's theme-API expectations). |
yarn test | Alias for yarn lint. |
yarn vitest | Runs the unit tests (transcript / chapters parsing and related helpers). |
yarn zip | Run test + build, then package signal.zip for upload. Excludes node_modules, .git, demo files, scripts, tests, and other source-only files. |
File map
The repo's root templates and key partials at a glance.
Templates (root)
| File | Purpose |
|---|---|
default.hbs | Master layout — the persistent player host (#mp-player-host), routing chrome, and the dark-mode resolver. |
index.hbs | Homepage: hero (six layouts) plus the platforms band, featured, hosts, guests, about, sponsors, support, and newsletter sections. |
post.hbs | Episode page: video/audio hero, tabs (show notes, chapters, transcript, comments, hosts & guests), up-next sidebar. |
page.hbs | Generic page wrapper. |
page-episodes.hbs, page-blog.hbs | The /episodes/ and /blog/ collection archives. |
page-subscribe.hbs, page-guests.hbs, page-hosts.hbs, page-contact.hbs, page-library.hbs | The slug- and route-activated special pages. |
tag.hbs, author.hbs | Topic and people (guest/host) archives. |
error.hbs, error-404.hbs | Error pages. |
Key partials
| Partial | Purpose |
|---|---|
partials/site-header.hbs, site-footer.hbs, mobile-menu.hbs | Header (logo, nav, search, member links), footer, and mobile drawer. |
partials/home/*.hbs | The homepage hero variants and sections. |
partials/episode/*.hbs | The episode page tabs and components (title block, audio hero, tabs, transcript, chapters, people, up-next). |
partials/media/*.hbs, partials/audio-player.hbs | The media stage and audio player. |
partials/library/*.hbs | The Library header widget and per-episode bookmark toggle. |
partials/icons/*.hbs | Single-path SVG icons, including social brand marks. |
Assets
| Path | Purpose |
|---|---|
assets/css/index.css | Tailwind v4 entry, design tokens, typography. Feature styles split into components.css, players.css, prose.css. |
assets/js/index.js | Entry point — wires the chrome-once and reinit module lifecycles. |
assets/js/signal-core/*.js | The content-swap router, theme resolver, Library stores, watch-progress, and members-form rebinding. |
assets/js/media/*.js | The player engine, media stage, audio player, source extraction, and transcript/chapters parsing. |
vite.config.js | Vite build config. |
i18n workflow
Signal currently ships English only (locales/en.json), and the yarn lint:i18n parity check is enforced — never add a {{t "..."}} call to a template without also adding the matching key to locales/en.json.
- Add the key to
en.jsonfirst, then reference it in the template. - Use Ghost's interpolation syntax (
{{t "Members of {site}" [email protected]}}) instead of string concatenation, so word order stays correct if a locale is ever added. - Never hardcode user-visible English in a template.
To translate the interface, a self-builder can add a locale file (for example locales/fr.json) with the same keys; Ghost loads it based on the site's publication language.
The data-* hook contract
Signal's templates carry a documented styling API — the data-region / data-component / data-variant / data-part attributes. If you fork the theme, treat these as public contract: site owners build Code-injection CSS against them, and renaming or removing one breaks that CSS. Add new hooks freely (and document them), but keep existing names stable. The full vocabulary: Hook reference.