Build and Release Guide
This guide applies to the dev branch of the Kawaikara repository.
Prerequisites
- Node.js 22 or newer.
- pnpm 10 or newer. The repository pins pnpm
10.33.0inpackage.json. - The local KawaiUI package expected by
@kawaikara/kawai-ui: link:../../KawaiUi. - Platform tools required by electron-builder for the target operating system.
- Castlabs EVS access for Widevine VMP-signed distributable builds.
- Apple Silicon native Video builds require libmpv headers and libraries from
Homebrew’s
/opt/homebrewprefix.MPV_INCLUDE_DIR,MPV_LIB, andMPV_RUNTIME_DIRcan override those paths. - Windows x64 native Video builds require a libmpv development runtime below
%USERPROFILE%\libmpvor the sameMPV_*overrides.
Intel macOS and other unsupported libmpv targets intentionally skip the native add-on build and package the Chromium/HLS compatibility backend instead.
Install workspace dependencies:
pnpm install
The app uses Castlabs Electron 40.10.6+wvcus. This keeps Widevine support on the runtime already validated for Kawaikara’s media and audio paths. At runtime, startup waits for the Widevine component before creating the viewer so DRM sites do not race CDM installation.
Environment file
Copy .env.example to .env.local and fill the Castlabs credentials when packaging DRM-capable builds:
KAWAIKARA_EVS_ACCOUNT=your-castlabs-account
KAWAIKARA_EVS_PASSWORD="your-castlabs-password"
The scripts first honor KAWAIKARA_EVS_PYTHON and
KAWAIKARA_EVS_CONDA_ENV, then inspect the active virtual/Conda environment,
project .venv-evs and .venv directories, the conventional Conda environment
named vmp, and available system Python commands. Optional overrides are useful
when EVS is installed elsewhere. .env.local is private and must not be
committed.
One supported local setup is:
conda create -n vmp python=3.10
conda run -n vmp python -m pip install castlabs-evs
Both account and password must be present together. Packaging scripts reject a half-configured credential pair.
Development commands
| Command | Purpose |
|---|---|
pnpm dev |
Build packages/app in development mode and start Electron |
pnpm build:packages |
Build site-api, then builtin-sites |
pnpm build:app |
Production webpack build for Main, Preload, and Renderer |
pnpm build |
Build workspace packages and the production app bundle |
pnpm start |
Build and launch Electron |
pnpm typecheck |
Type-check packages, app, and Storybook |
Webpack emits:
dist/
├── main/main.js
├── preload/
│ ├── preload.js
│ └── viewer.js
└── renderer/
├── index.html + overlay.js
├── video.html + video.js
└── external-login.html + external-login.js
Build-time constants include the release channel and optional Discord application ID. Set DISCORD_APP_ID before building to enable Discord Rich Presence; an empty value disables it without failing startup.
Storybook
Run the app-owned view and component catalog without Electron:
pnpm storybook
Storybook listens on port 6006, loads KawaiUI and renderer styles, and installs stories/Mocks/KawaikaraMock.ts before each story. Stories currently cover Menu, Preference, Video, developer links, external-login status, update-panel states, PiP controls, site menu controls, and the downloader panel.
Create a static Storybook build with:
pnpm storybook:build
Development package
pnpm package:dev
The script:
- Requires the current
Kawaikara Devapplication to be stopped on macOS. - Authenticates EVS when credentials are configured.
- Runs the development build.
- Packages the current platform/architecture through
electron-builder.dev.config.cjs. - Replaces the managed output atomically and restores the previous build if packaging fails.
- On macOS and Windows, opens the packaged application once so the OS registers
kawaikara://.
Development output is placed below:
builds/dev/<os>/<arch>/
The development package uses app ID day.faby.kawaikara.dev and product name Kawaikara Dev. macOS certificate auto-discovery is disabled for this local package, but Widevine VMP signing still runs when KAWAIKARA_VMP_SIGN=1.
Verify the package signature and Widevine VMP state with:
pnpm widevine:verify
Authenticate EVS explicitly with:
pnpm widevine:auth
Release channels
Kawaikara has three build/update channels:
| Build channel | Version shape | Updater channel | GitHub release type |
|---|---|---|---|
| Stable | 3.0.0 |
latest |
Release |
| Staging | 3.0.0-staging.YYYYMMDD.RUN.ATTEMPT.gSHA |
staging |
Prerelease |
| Nightly | 3.0.0-nightly.YYYYMMDD.RUN.ATTEMPT.gSHA |
nightly |
Prerelease |
The package script temporarily changes package.json to the calculated release version, builds/packages, and restores the original file in a finally block.
The build number defaults to GITHUB_RUN_NUMBER, or 0 outside CI. KAWAIKARA_RELEASE_VERSION can supply an explicit valid version.
Stable publishing still accepts a v3.0.0 tag or a manual workflow run. Staging and Nightly do not use source-repository tags:
.github/workflows/nightly.yamlselects an immutable commit fromdevevery day at 00:00 KST. It can also be run manually..github/workflows/staging.yamlis manual and defaults to the latestdevcommit.- A manually supplied source SHA is rejected unless it belongs to
dev. - The same source commit is not published twice unless
forceis selected. - Release notes and
channel-source.jsonrecord the exact source repository, branch, commit, and Actions run.
The generated releases are published to separate public repositories:
| Channel | Release repository | Anchor branch |
|---|---|---|
| Stable | fabyday/kawaikara |
release tag target |
| Staging | Kawaikara/kawaikara-staging |
staging |
| Nightly | Kawaikara/kawaikara-nightly |
nightly |
Site API releases
External Bundle projects do not resolve @kawaikara/site-api from the npm
registry. The stable contract is released independently with an immutable
vX.Y.Z Git tag and a prebuilt .tgz GitHub Release artifact in the dedicated
Kawaikara/kawai-site-api
repository.
The API repository owns its source tag and release.yaml. Pushing a matching
tag, for example v1.0.0, validates the package, packs and tests an isolated
tarball, and attaches that tarball to a GitHub Release. No NPM_TOKEN is
required. KawaiBundleTemplate pins that immutable .tgz, so a fresh clone has
a reproducible API dependency without a local link: path or monorepo build.
The desktop repository no longer owns a Site API release tag or workflow.
The scheduled workflow file itself must exist on the source repository’s default branch because GitHub only starts scheduled workflows from that branch. The workflow still checks out and validates dev, so merging the workflow definition into main does not make main a Nightly source. Staging is the beta-equivalent channel; there is intentionally no separate beta channel.
Development-channel publishing uses a GitHub App instead of long-lived personal access tokens:
- Create a GitHub App owned by
Kawaikarawith repositoryContents: Read and writepermission. - Install it with access limited to
kawaikara-stagingandkawaikara-nightly. - Store its Client ID as the Actions repository or organization variable
KAWAIKARA_RELEASE_APP_CLIENT_ID. - Generate a private key and store the complete PEM value as the Actions
secret
KAWAIKARA_RELEASE_APP_PRIVATE_KEY.
The workflow uses actions/create-github-app-token@v3 to mint a repository-
scoped installation token for each job. Prepare receives read-only Contents
permission; publishing receives write permission. The action revokes each token
when its job finishes. STAGING_RELEASE_TOKEN and NIGHTLY_RELEASE_TOKEN are
no longer used.
Keep the existing EVS, signing certificate, and Discord secrets used by Stable publishing.
Versioned release notes live under CHANGELOG/<base-version>. English and
Korean patch-note files are required; Japanese is optional. The workflow builds
the GitHub Release body from those files, and the in-app Update Notes view picks
the current app language with English fallback.
Stable versions may not contain a prerelease suffix. Staging and Nightly versions must begin with their corresponding prerelease name.
Build-only and publish commands
| Channel | Build without publishing | Build and publish |
|---|---|---|
| Stable | pnpm dist:stable |
pnpm release:stable |
| Staging | pnpm dist:staging |
pnpm release:staging |
| Nightly | pnpm dist:nightly |
pnpm release:nightly |
Automatic tag-based publishing remains available for local/legacy use, but the GitHub workflow uses it only for Stable:
pnpm release:auto
All channel packaging commands set KAWAIKARA_VMP_SIGN=1, authenticate EVS when credentials are available, run the full build, and invoke electron-builder.
Platform artifacts
Release output is grouped by channel and operating system:
builds/<channel>/<os>/
Configured targets are:
- macOS: DMG and ZIP for x64 and arm64.
- Windows: NSIS installer and ZIP for x64.
- Linux: AppImage for x64 and arm64.
The artifact name includes product, version, channel, OS, architecture, and extension. The application registers the kawaikara:// protocol.
Update behavior
electron-updater is configured with automatic install-on-quit disabled. Automatic update checks are also disabled by default in Preferences.
Every package is permanently bound to its build channel and release repository. Stable only reads latest metadata from fabyday/kawaikara, Staging only reads staging metadata from Kawaikara/kawaikara-staging, and Nightly only reads nightly metadata from Kawaikara/kawaikara-nightly. The application does not permit cross-channel upgrades or downgrades.
Manual checks open the update overlay and report checking, update-available, up-to-date, unsupported, or error states. A found update exposes a separate, scrollable Update Notes view before the user starts the download.
Automatic startup checks remain completely hidden while checking and when no
release is available. Once a newer release is found, the download panel appears,
downloads immediately, and relaunches Kawaikara after the package is ready.
Update checks return unsupported in a non-packaged development run.
Discord presence
If DISCORD_APP_ID was embedded during webpack build and a Discord client is available, startup publishes Kawaikara Rich Presence with project/Discord buttons and configured image asset keys. Failure to connect is non-fatal, and shutdown clears/destroys the client.
Pre-release checklist
pnpm typechecksucceeds.pnpm storybook:buildsucceeds.pnpm buildsucceeds from a clean dependency install.- The packaged build passes
pnpm widevine:verify. - DRM playback is tested with isolated site profiles.
- Login popup and external-browser flows are tested with a real account.
- Unified PiP enters, moves, resizes, and restores focus on landscape and portrait video.
- File drop and HLS playback work in the internal Video view.
- The release version matches its channel rules.
- GitHub updater metadata and all intended artifacts are present before publishing to users.