Orkige Help DownloadOrkige

Help portal

The engine's public site lives at orkige.orkitec.com. It is regenerated and deployed by CI on every push to main (.github/workflows/pages.yml) — nothing on a dev machine serves it, and the editor's Help > Orkige Help simply opens the published documentation in the default browser (a network connection is required — a distributed editor carries no repository and no python toolchain, so it cannot generate the site itself).

The deployed site has these parts:

  • / — the landing page: the engine's story (tagline, platform pitch,

    feature highlights distilled from the repository README) with links into the documentation, the API reference, the live benchmark and the repository, and the Downloads section the first hero button jumps to. The landing page itself stays embed-free.

  • /benchmark — the live benchmark page: the engine's benchmark showcase

    (projects/benchmark), compiled to WebAssembly and embedded in a 16:9 frame directly below the site header, with context prose beneath it. It is reached from the landing page's "Benchmark" nav button and loads the player on arrival (visitors navigate here deliberately). The iframe is never wider than the text column and scales down with it on narrow screens; its src is the staged export at /play/.

  • /play/ — the staged browser build the benchmark page embeds: a

    self-contained wasm export of projects/benchmark (index.html + orkige_player.js/.wasm + a preloaded .data payload image), produced by orkige_export --platform web. Like /api/, it is assembled by the Pages workflow beside the generator's output — a local portal preview lacks it, and links to it are the second site-absolute target the link gate accepts on faith.

  • /help/ — the documentation portal: the repository README.md (the

    Overview page), every Docs/*.md (this page included), and any projects/*/README.md — searchable, cross-linked, generated by Util/make_help_portal.py (python3 stdlib only, like every Util/ tool).

  • /help/changelog — the full history: every commit, grouped by the day it

    landed. A day that published a nightly is headed by that build's ordered version identity; every other day is headed by its date and the retroactive version era it falls in. It is the only portal page with no committed source file: the repository's git history is the record, and the page renders from it at deploy time through the composition in Util/orkige_nightly_package.py — the same text the nightly's own changelog and its release asset come from, read once rather than parsed two ways. Nothing generated is ever committed back. The page is in the nav and deliberately out of the search index: a thousand commit lines would stand in front of the guide a search is looking for. Both jobs that build the site check out with fetch-depth: 0, which brings the nightly-YYYYMMDD release tags the published days are read from; from a shallow clone the page says the history it lists is truncated, tags it could not read leave every day unmarked and say so, and with no git history at all it says nothing is listed rather than rendering empty.

  • /api/ — the C++ class reference, rendered from the orkige_core/ and

    orkige_engine/ headers by Docs/api/Doxyfile. That tooling is CI-only: the Pages workflow installs it on the runner and assembles the output next to the portal, so dev machines need no extra installs.

  • /imprint and /privacy — the legal pages (Docs/legal/imprint.md,

    Docs/legal/privacy.md), linked from a footer that appears on every page of the site, the API reference included. They stay out of the nav and the search index — footer-only is the convention.

Downloads, and the moving asset URLs

The landing page carries a Downloads section: one card per desktop platform, each offering the installable artifact and the portable archive of that night's build, with the caveats that platform actually has — Docs/nightly-builds.md is where those come from, and the section links it.

The constraint that shapes the whole section is that there is no stable asset URL. A nightly asset's filename carries the version and the commit (Orkige-macos-2.0.0-nightly.20260731_498a82b2a.dmg), so it changes every night, while this site is static and regenerates only when the repository does. Three ways to bridge that gap, and one of them wins:

ApproachWhy not / why
Hardcode the asset URLsStale within a day, then a 404.
GitHub's /releases/latest/download/<name>Needs a FIXED asset name, and latest skips prereleases — every nightly is one. Unavailable twice over.
Link the release pageAlways correct and never rots, but hands the visitor the whole asset list — six archives, a checksum sidecar beside each and the changelog — to pick their platform's two out of.
Link the release page, then resolveThe chosen one: the release-page link IS the markup, and a script upgrades it to the night's real asset URL.

So help/downloads.js asks the releases API for the nightly release (GET /repos/orkitec/orkige/releases/tags/nightly, the same request an updater makes) and rewrites each button in place — the real download URL, the size in megabytes, the ordered version read from the release notes' orkige-nightly-version marker, and an accent on the card the visitor's own platform is most likely to be.

The fallback is the normal state of the markup, not an error path. Every button ships pointing at the release page and every caveat is in the HTML before a byte of script is fetched, so no JavaScript, no network, a blocked script file, an API shape we do not recognise, or the unauthenticated rate limit (60 calls an hour per address, Docs/nightly-builds.md) all leave a page that is complete and correct — one click longer, never broken. Nothing in the section is ever emptied, reordered or hidden by the script, and a platform whose build produced no artifact tonight keeps its release-page link and says not in this build rather than promising a file that is not there. Platform detection is the same: it only ever adds an accent, and an unrecognised user agent (or a tablet reporting a desktop one) simply highlights nothing while every platform stays visible.

One table in Util/make_help_portal.py drives both sides — the asset-name patterns and the user-agent rules are emitted into the script verbatim, and matched by the generator's own match_download_asset and detect_download_platform in the selftest, so the browser and the test can never disagree about which file belongs on which button.

The section's links into the docs corpus go through the same broken-link gate the authored prose does: GENERATED_DOC_LINKS names every corpus page and heading anchor a generated page points at, and a renamed doc or retitled heading fails the build with the usual file:line report instead of shipping a 404.

Local preview

python3 Util/make_help_portal.py --output /tmp/orkige-site   # build the site
python3 Util/make_help_portal.py --output <dir> --if-stale   # skip when current
python3 Util/make_help_portal.py --selftest                  # the unit ctest

Everything is relative-linked, so opening <dir>/index.html straight off the disk works. A local preview lacks /api/ — the generator stays stdlib-only and never runs the API tooling; if you want the class reference locally, render it yourself with the same config the workflow uses (doxygen Docs/api/Doxyfile, output under the gitignored Docs/api/build/) and move html/ to <dir>/api.

How docs authors see their pages

The portal PRESENTS the corpus — write normal repository markdown and it renders as written. Because python has no stdlib markdown library, the renderer is a subset tailored to what the corpus actually uses:

  • ATX headings (#######), paragraphs, horizontal rules.
  • Nested unordered/ordered lists, continuation lines, and fenced code blocks

    indented inside list items.

  • Fenced code blocks with a language tag (rendered as plain preformatted

    code — mermaid blocks included, which appear as their source text).

  • Pipe tables with the \| cell escape and :---: alignment.
  • Inline code, **bold**, *italic*, links and images.
  • HTML comments (the GENERATED block markers) are stripped from the output.

Heading anchors use the familiar slug rules (lower-case, punctuation dropped, every space becomes a dash — ## Show / hide transitions anchors as #show--hide-transitions), so [text](gui.md#section) links written for the repository browser work in the portal unchanged.

Link semantics keep the site self-contained and honest:

  • A link to another corpus page (lua-api.md, ../README.md, optionally

    with #anchor) becomes a site page link — and is verified: a target page or heading anchor that does not exist fails the build, reported as BROKEN LINK <file>:<line> -> <target> so the author can fix the exact spot. Because the Pages workflow runs this generator, the broken-link gate is also the deploy gate; the make_help_portal_selftest ctest keeps the real corpus at zero broken links locally, before a push ever reaches CI.

  • A link to /api/ is the ONE allowlisted target with no corpus page behind

    it — the Pages workflow assembles the class reference there.

  • A link to a repository file outside the corpus (a header, LICENSE)

    renders as inline code — there is no page to link to.

  • External http(s) links stay links; images degrade to their alt text (the

    portal ships no images and never fetches remote ones).

The API reference

Docs/api/Doxyfile renders the full public surface of orkige_core/ and orkige_engine/ (EXTRACT_ALL, so classes appear even where the 2009-era comments are sparse; warnings are logged, never fatal). Docs/api/footer.html puts the site-root link and the imprint/privacy links on every generated page. The check_doxyfile ctest validates the config by rendering the real tree when the tool is installed and skips honestly (exit 77) when it is not.

Delivery

The per-push deploy is the site job inside .github/workflows/ci.yml, so one push shows one run: generate the site, render /api/, write the CNAME for the custom domain, upload and deploy to GitHub Pages (concurrency-grouped, so a newer push supersedes an in-flight deployment).

The /play/ embed is gated behind the WebGL suite. The web job exports the benchmark (orkige_export --platform web) only after its WebGL suite (ctest --preset web, incl. the headless-Chrome boot) passes, and uploads the export as an artifact; the site job is needs: web and unpacks that artifact into /play/. So a commit that breaks WebGL fails the web job, the site job is skipped, and the last good deployment — docs and a working player — stays live rather than being rebuilt onto a broken build. The export artifact is reused, so the site job runs no second wasm build.

.github/workflows/pages.yml is the manual workflow_dispatch lever — a site nudge without the whole test matrix. Being standalone (no web job to reuse), it cross-builds the wasm player itself (modeled on ci.yml's web job: pinned emsdk + vcpkg, binary/ccache caches keyed identically), runs the same WebGL suite as a gate, then exports /play/ and deploys. A broken WebGL build fails that gate, so a manual redeploy never stages a broken player either.

Repository one-time setup: Settings → Pages → Source "GitHub Actions", custom domain orkige.orkitec.com (DNS: a CNAME record pointing orkige.orkitec.com at orkitec.github.io), then Enforce HTTPS.

Verified by make_help_portal_selftest (unit: synthetic + real corpus, balanced HTML on every page, zero broken links, legal-footer and search conventions, stamp logic, the download asset/platform matchers against real artifact names — sidecars included — and the shipped Downloads markup with every button still a release-page link; the site's two hand-written scripts are additionally run through node --check where node is installed, because a stray escape in a python string literal is otherwise invisible until a browser refuses the file), check_doxyfile (unit, skips without the tooling) and editor_help_portal (integration: the Help menu action resolves the published URL and the automated-run browser gate holds — no network in tests).