scmJS docs

Releases

.github/workflows/build.yml has three channels, and the release list only grows when a version is cut:

channel trigger what lands
ci every push to main, and every pull request against it lint, the tests (vitest and the browser tests) and the web bundle, built and thrown away. Nothing is deployed and nothing is released. A pull request's run is read-only and does not publish the plugin typings.
nightly a daily cron at 07:17 UTC, or a manual dispatch with the nightly input ticked installers for Windows, macOS (x64 and arm64) and Linux (AppImage and deb), a zip of the web bundle and the updater's latest*.yml, all on one rolling prerelease, plus the same commit built for /nightly/ and served at scmjs.dev/nightly.
stable a pushed vX.Y.Z tag a permanent release with the same assets, its notes, the container image on GHCR, the Pages deploy of scmjs.dev/editor, and the docs site.

The cron exits early when main has not moved since the last nightly. The nightly is updated in place: its nightly tag is force-moved and its assets replaced, never deleted and recreated, so there is one prerelease in the list however many nights run. Its notes link scmjs.dev/nightly, which is that same commit running, so the release page is somewhere to try it from as well as somewhere to download it from.

GitHub redirects /releases/latest/download/<asset> to the newest release that is not a prerelease or a draft, so the download buttons on the site are plain links that never need updating and never resolve to a nightly:

https://github.com/scm-js/scm-js/releases/latest/download/scmJS-windows-x64-setup.exe
https://github.com/scm-js/scm-js/releases/latest/download/scmJS-windows-x64.zip
https://github.com/scm-js/scm-js/releases/latest/download/scmJS-macos-arm64.dmg
https://github.com/scm-js/scm-js/releases/latest/download/scmJS-macos-x64.dmg
https://github.com/scm-js/scm-js/releases/latest/download/scmJS-linux-x86_64.AppImage
https://github.com/scm-js/scm-js/releases/latest/download/scmJS-linux-amd64.deb
https://github.com/scm-js/scm-js/releases/latest/download/scmJS-web.zip
https://github.com/scm-js/scm-js/releases/download/nightly/scmJS-windows-x64-setup.exe

That redirect can only resolve a fixed file name, which is why the asset names carry no version; the version is in the release title, the notes and latest*.yml. To un-promote a bad release, tick "This is a pre-release" on it and the redirect falls back to the one before.

The container image#

docker/Dockerfile is nginx with the built web bundle, pushed to ghcr.io/scm-js/scm-js by the image job on a tagged release only, as latest, the full version, and the moving X.Y and X. A nightly publishes no image, because latest is what a docker run picks up without asking.

docker run --rm -p 8080:80 ghcr.io/scm-js/scm-js:latest   # http://localhost:8080
npm run build:image                                       # build it locally, tagged scmjs

The image copies the release's own web zip rather than building one, so the editor in it cannot differ from the download; the one addition is the default plugins' runtimes (see the desktop build above), which the zip leaves to the CDN. With no RUN step one buildx manifest covers linux/amd64 and linux/arm64 without emulation. It carries no game data: .dockerignore cuts the extracted trees out of the build context and docker/nginx.conf answers 404 for those paths, so a container asks through Help ▸ Game Data… like the hosted build. Mounting an extracted tree over those paths is in game-data.md.

Cutting a release#

Run the Release workflow (.github/workflows/release.yml) from the Actions tab. It takes the version (0.3, 1.0 and 1 are padded to three parts; blank promotes the line the nightlies have been building), an optional notes box, and a dry_run tick that does everything except push.

It refuses to run anywhere but main, refuses a version whose tag exists, refuses one that is not newer than the last release, and runs lint, tests (the network suite included), the build and a check of the container image before writing anything. Then it commits the version into package.json and the lock file, tags that commit vX.Y.Z, and dispatches the Build workflow on the tag. The dispatch is necessary because a push made with the repository's own token starts no further workflow run; that one dispatch is the whole release, the hosted editor and the docs site included.

There is no step moving package.json on to a next version. A nightly is named <base>-nightly.<date>.<run number> where the base is a patch bump of the newest release tag, worked out by scripts/next-version.mjs. A patch bump is the one choice that sorts above the release it follows and below whatever comes next, whether that is a patch, a minor or a major, so the updater is never offered a downgrade and never starved. It also leaves package.json on main meaning something true: the last released version.

Release notes#

The hand-written part of a release comes from docs/releases/<version>.md, committed to main before the release is cut and read from the tag's own tree (the full three-part name: cutting 0.3 reads 0.3.0.md), or from the Release workflow's notes input, which wins over the file and lives only in the release. Either goes above GitHub's generated list of commits; with neither, the release carries that list alone. The pre-flight prints what it found, so a dry run shows the body. docs/releases/README.md is the convention.

Versions#

The version is the tag's, or the nightly name on main. Every job writes it into package.json before building; vite.config.ts injects it as __APP_VERSION__, src/version.ts is where the splash and About read it, the boot splash in index.html gets it through a small Vite plugin, and electron-builder writes it into latest*.yml. The run number rather than a commit hash orders same-day nightlies, since semver compares prerelease identifiers as strings.

The two hosted builds#

deployed by from
scmjs.dev/editor the pages job, on a tag GitHub Pages on this repository, built for the /editor/ path (the PAGES_BASE repository variable) and served there by a Cloudflare Worker in front of it
scmjs.dev/nightly the nightly-site job, each nightly the same commit built for the /nightly/ path (the NIGHTLY_BASE repository variable) with SCMJS_SITE=nightly, in the nightly/ folder of one force-pushed orphan commit on scm-js/nightly's gh-pages branch, served there by the Cloudflare Worker; the branch's root keeps the old nightly.editor.scmjs.dev address sending people on, and its moved.html hands their settings over
docs.scmjs.dev the docs job, on a tag the same shape, on scm-js/docs

The hosted editor is a release like every other way of running the editor: the site, the installers, the image and the notes are one tag. The nightly site is the nightly's own web zip unpacked, never a second build, which is why the nightly's notes can point at it: the page and the installers on that release are the same version. To put scmjs.dev/editor back on an older version, dispatch Build on that tag; the deploy is the only thing a re-run rewrites.

The two editors share the scmjs.dev origin, and with it the browser's storage, because the nightly needs the game's page at /play/ beside it. The nightly keeps its own preferences, recents and plugins under names of its own, rather than writing a stored shape the stable build then reads back. The extracted game data is the exception: the game's page reads the one copy in the origin's private file storage, so the nightly installs it there too, and one install serves both editors and Test Map. A nightly that changes how that copy is stored has to keep it readable by the last release.

Variables and secrets#

None of these is required: a fork builds and releases without any of them, and each deploy that lacks its own is skipped with a notice.

Kind For
PAGES_BASE variable The hosted editor's base path: / for a custom domain, the repository name by default. When it is not /, the web job builds a second bundle for Pages, since the release zip is always rooted.
NIGHTLY_DOMAIN variable The domain written into the nightly site's CNAME.
NIGHTLY_PAT repository secret A fine-grained token with Contents: write on <owner>/nightly, since a repository's own token cannot write to another repository.
DOCS_DOMAIN, DOCS_PAT variable, repository secret The same pair for the docs site on <owner>/docs.
PLUGIN_API_PAT organisation secret Pushes the plugin typings to scm-js/plugin-api.
PUBLISH_PLUGIN_API variable Turns on the npm publish of @scm-js/plugin-api.

scmJS 0.7.3 + main@e2d8ba5 · Generated from the repository. The source is under the MIT license, which does not cover what ATTRIBUTION.md lists. StarCraft and Brood War are trademarks of Blizzard Entertainment; this project ships none of their data.