A persistent podcast/radio audio player for Hugo: drop <podcast-player> into any page with a single shortcode. Supports local files, AzuraCast radio streams, and iVoox episodes. Works as a Hugo module and as a Hugo theme.
Wavecast provides two custom Web Components that work together:
| Component | Where | What it does |
|---|---|---|
<podcast-player> |
Inline (in your content) | Play/pause, skip, seek, volume, chapters, poster |
<podcast-footer> |
Sticky footer | Persistent player bar that follows you across every page |
Both components are bidirectionally synced: pausing the footer pauses all inline players, and vice versa. Only one audio source plays at a time. Position, volume, mute, and speed survive page navigation.
- Web Component with Shadow DOM: framework-agnostic, works anywhere
- Inline player: play/pause, skip +-15s, seekable progress bar, volume slider, mute, playback rate (0.5x-2x)
- Sticky footer player: cover art, track name, skip, play/pause, progress bar, volume, mute, speed, close
- Bidirectional sync between inline and footer players
- Single-stream: playing a new source stops the previous one automatically
- Chapters: timestamp-labelled navigation chips
- Poster and description: cover image with responsive sizing, Markdown-rendered show notes
- Source adapters: local files, AzuraCast, iVoox (with auto-detection)
- Navigation persistence: survives Turbolinks, Turbo, htmx, and vanilla page loads
- CSS custom properties for light/dark themes, responsive on mobile
::part()selectors: style individual Shadow DOM elements from outside- Keyboard shortcuts: Space (play/pause), Left/Right (skip), M (mute)
- Media Session API: integrates with OS media controls
- Podcast RSS feed: iTunes-compatible feed generation from Hugo content
- Accessible: ARIA labels,
:focus-visiblerings, semantic controls
{{< podcast-player
src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"
title="Episode 42: Hello World"
poster="https://picsum.photos/seed/podcast/400/400"
description="Show notes with **Markdown**."
chapters="00:00:00-Intro,00:05:30-News,00:15:00-Interview"
>}}Place audio files in your Hugo project's assets/ directory and use src="episodes/my-episode.mp3" for local playback.
Add the sticky footer to layouts/_default/baseof.html just before </body>:
<podcast-footer id="podcast-footer"
data-turbolinks-permanent data-turbo-permanent hx-preserve>
</podcast-footer>Prerequisites: Hugo v0.146.0+, Go 1.23+ (module install only)
Theme (recommended for most sites):
git clone git@github.com:adurrr/wavecast.git themes/wavecast# hugo.toml
theme = "wavecast"Module (for multi-module sites):
hugo mod get github.com/adurrr/wavecast# hugo.toml
[module]
[[module.imports]]
path = "github.com/adurrr/wavecast"Run the demo:
git clone git@github.com:adurrr/wavecast.git
cd wavecast/exampleSite
hugo server --port 1313Full documentation is built into the live demo site and the example site (run locally to browse). Each page includes working code examples:
| Page | Covers |
|---|---|
| Welcome | Overview, features, navigation |
| Installation | Theme vs module, version pinning |
| Getting Started | First episode, parameters |
| Configuration | Global defaults, CSS properties, ::part() selectors |
| Homepage Setup | Footer player, framework attributes |
| Utility Shortcodes | Admonitions, buttons, figures, tabs, galleries |
| Front Matter | Audio fields, podcast RSS fields |
| Advanced | Source adapters, events, persistence, troubleshooting |
The docs include a Spanish translation at /es/docs/.
assets/
css/podcast-player.css # External stylesheet (light theme, responsive, focus-visible)
js/podcast-player.js # Web Component + source adapters + persistence (~1790 lines)
js/sources.js # Re-exports for test imports
demo/demo-audio.wav # Demo audio file for the example site
layouts/
_default/
rss.xml # Podcast RSS template (auto-detects podcast config)
_shortcodes/
podcast-player.html # Hugo shortcode template
tests/
hugo/ # Go integration tests (builds Hugo sites per case)
js/ # Vitest unit tests
e2e/ # Playwright E2E tests
exampleSite/ # Runnable demo site with built-in documentation
theme.toml # Hugo theme manifest
npm test # JS unit tests (Vitest + jsdom)
go test -v -timeout 120s ./tests/hugo/... # Go integration tests
npm run test:e2e # E2E tests (Playwright + Hugo server)
npm test && go test ./tests/hugo/... && npm run test:e2e # All tests- Create a new class in
assets/js/podcast-player.jsimplementingfetchStreamUrl()and/orfetchMetadata() - Register it in the
sourceAdaptersmap - Add auto-detection rules in
_detectSource() - Write JS unit tests in
tests/js/and E2E tests intests/e2e/ - Run all three test suites
AGPLv3
