Skip to content

basilica-audio/website

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Basilica Audio — Product Website

Static product site for the Basilica Audio plugin suite — thirteen sacred-architecture DSP plugins for heavy music. Zero frameworks, zero external dependencies: a small Python (stdlib-only) generator renders a bilingual (English + German) site: an overview page, one product page per plugin, and one user-manual page per plugin (where a manual exists), each mirrored under /de/.

Deployed via GitHub Pages on every push to main (.github/workflows/pages.yml builds dist/ and publishes it — dist/ is never committed).

Structure

build.py                  Generator + internal link checker (python3 stdlib only)
lib_md.py                 Vendored, dependency-free Markdown -> HTML renderer (manual pages only)
data/plugins.json         Plugin content: names, roles, taglines, features, media
                           — each plugin may carry a "de" object (see "Translating
                           plugin content" below); chrome strings live in build.py instead.
data/manuals/<slug>.en.md English user manual, synced verbatim from the plugin repo
data/manuals/<slug>.de.md German user manual (optional — see "Manual sync" below)
templates/base.html       Page shell (header incl. language switch, footer)
templates/index.html      Overview page (hero + card grid)
templates/plugin.html     Product page (about, features, downloads, stubs, links)
templates/manual.html     User-manual page (breadcrumb + rendered manual article)
assets/css/style.css      Suite stylesheet (charcoal + antique gold, system fonts)
assets/js/releases.js     Client-side latest-release download buttons
assets/icons/<slug>.png   Plugin icons (256 px)
assets/org.png            Org emblem (512 px)
dist/                     Build output (gitignored, built in CI)

Every generated page lives at <dir>/index.html under dist/, mirrored once for English at the site root and once for German under dist/de/:

/                          English overview
/<slug>/                   English product page
/<slug>/manual/            English user manual (only if data/manuals/<slug>.en.md exists)
/de/                       German overview
/de/<slug>/                German product page
/de/<slug>/manual/         German user manual (only if data/manuals/<slug>.de.md exists)

assets/ is shared by both language trees (copied once to dist/assets/) — nothing is duplicated per language except the HTML pages themselves.

Local preview

python3 build.py
python3 -m http.server -d dist
# open http://localhost:8000

build.py fails the build if any generated page contains a broken internal link, so a green build means the site is internally consistent — across both language trees.

Configuration

The GitHub org login lives in one place: the ORG constant at the top of build.py. Templates and the client-side release fetcher (via <body data-org="...">) both receive it from there. When the org is renamed from metal-up-your-ass to basilica-audio, change only that constant and rebuild.

Internationalization (English + German)

URL structure. The existing English tree stays exactly where it was (site root, /<slug>/) so no existing link breaks. The German tree is a full mirror under /de/ (/de/, /de/<slug>/), generated by the same templates with lang="de".

UI chrome strings. Every piece of site chrome — nav labels, the download button, the "no screenshots yet" empty state, the donations stub, footer copy, "User manual", breadcrumb back-links, etc. — comes from the STRINGS = {"en": {...}, "de": {...}} dict at the top of build.py. There is exactly one exception: the one string assets/js/releases.js renders client-side ("Release notes & previous versions") is injected per-page via a data-release-notes-label attribute sourced from the same STRINGS dict, so it stays localized too. DSP/product terminology (Mix, Bypass, Threshold, dB, plugin format names, ...) is deliberately left in English in the German column — that's how German-speaking audio engineers actually talk about these controls.

Language selector. Every page header carries an "EN | DE" switch (lang_switch_nav() in build.py) linking to the equivalent page in the other language. Clicking it stores the choice in localStorage.lang via a small inline onclick handler — no page-load JS dependency.

Root-index redirect. Only the root English index (/) carries a small inline script that redirects to /de/ if localStorage.lang === "de", or — absent a stored preference — if navigator.language starts with de. It fails open (stays on the English page) if localStorage/navigator are unavailable. The redirect target is a page-relative de/, so the site stays relocatable under any deploy path prefix.

hreflang. Every page emits <link rel="alternate" hreflang="en|de|x-default"> tags pointing at its sibling in the other language (hreflang_tags() in build.py).

Translating plugin content. data/plugins.json schema: each plugin object may carry an optional "de" object with any of "role", "tagline", "description", "features":

{
  "slug": "overture",
  "name": "Overture",
  "role": "Guitar tight boost",
  "...": "... (all the existing English fields, unchanged) ...",
  "de": {
    "role": "Gitarren-Tightening-Boost",
    "tagline": "...",
    "description": "...",
    "features": ["...", "..."]
  }
}

Any field missing from "de" — or a plugin with no "de" object at all — falls back to the English field (loc() in build.py). The site always builds cleanly with zero translations present; German product pages simply show English plugin copy until translated.

User manuals

Each plugin's manual is synced verbatim from its own repo into data/manuals/<slug>.en.md, from <plugin-repo>/docs/manual.md. The synced copy gets one generated-from HTML comment prepended (stripped again before rendering, so it never shows up in the built page):

<!-- Generated from <repo>/docs/manual.md on YYYY-MM-DD — do not hand-edit; re-run the manual sync described in website/README.md. -->

To re-sync a manual after the source repo's docs change:

cp ../<repo>/docs/manual.md data/manuals/<slug>.en.md
# then prepend the generated-from comment line above (with today's date)

<slug> is the plugin's site slug, <repo> is its GitHub repo name — these differ for one plugin: Crypta ships from the twist-your-guts repo (a pre-rename holdover), so data/manuals/crypta.en.md is generated from twist-your-guts/docs/manual.md.

If a plugin repo has no docs/manual.md, it simply has no data/manuals/<slug>.en.mdbuild.py skips its manual page entirely and drops the "User manual" link from that plugin's product page (it never renders a link to a page that doesn't exist).

German manuals (data/manuals/<slug>.de.md) are optional and mostly don't exist yet. When one is missing, the German product page's "User manual" link falls back to the English manual page with a small "(English)" hint appended, instead of hiding the link. Once a German manual file is added, build.py picks it up automatically on the next build — no code change needed.

Rendering. Manual Markdown is rendered by the small vendored renderer in lib_md.py (stdlib-only — see its module docstring for exactly which Markdown subset it supports: headings, paragraphs, bold/italic/inline code, fenced code blocks, links, ordered/unordered lists, GitHub-style tables, blockquotes, horizontal rules). Raw HTML in a manual's Markdown source is escaped, never executed. Manual pages get a dedicated .manual article layout in style.css; wide tables scroll horizontally inside their own .table-scroll container so they never widen the page itself. A manual's doc-relative links (e.g. architecture.md) are rewritten to point at that file on the plugin's GitHub repo, since the manual page itself doesn't host the rest of docs/.

Downloads

Each product page ships with a static fallback link to the plugin's GitHub releases page. On load, assets/js/releases.js queries https://api.github.com/repos/<ORG>/<Repo>/releases/latest and replaces the fallback with one styled button per .zip asset (platform, version, size, publish date). If the API call fails — offline, rate-limited, no release yet — the fallback link simply stays.

Adding screenshots and audio examples later

Product pages render honest "coming with the next release" empty states until real media exists. To populate them for a plugin:

  1. Drop files into assets/<slug>/ (create the directory), e.g. assets/requiem/main-window.png or assets/requiem/choir-before-after.mp3.

    • Screenshots: .png .jpg .jpeg .webp .gif
    • Audio: .mp3 .wav .ogg .flac .m4a
  2. Rebuild. That's it — the template auto-discovers the files (sorted by name; captions derived from the filename, main-window.png → "Main window").

  3. Optional: curate order and captions explicitly in data/plugins.json:

    {
      "slug": "requiem",
      "screenshots": [
        { "file": "main-window.png", "caption": "The main window" }
      ],
      "audio": [
        { "file": "choir-before-after.mp3", "caption": "Choir bus, before/after" }
      ]
    }

    When these fields exist they take precedence over auto-discovery.

Donations

The "Support development" section is a deliberate stub: visually present, buttons disabled, no real payment links. Wire up GitHub Sponsors / Ko-fi / PayPal in templates/plugin.html (see the HTML comment there) when the accounts exist.

License

The website sources are part of the Basilica Audio suite. All plugins are licensed under the GNU AGPL-3.0.

About

Basilica Audio — product pages for the plugin suite

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors