Home
GuideAPP Design · build

Build and Release Guide

This guide applies to the dev branch of the Kawaikara repository.

build/BuildAndRelease

Prerequisites

  • Node.js 22 or newer.
  • pnpm 10 or newer. The repository pins pnpm 10.33.0 in package.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/homebrew prefix. MPV_INCLUDE_DIR, MPV_LIB, and MPV_RUNTIME_DIR can override those paths.
  • Windows x64 native Video builds require a libmpv development runtime below %USERPROFILE%\libmpv or the same MPV_* 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:

  1. Requires the current Kawaikara Dev application to be stopped on macOS.
  2. Authenticates EVS when credentials are configured.
  3. Runs the development build.
  4. Packages the current platform/architecture through electron-builder.dev.config.cjs.
  5. Replaces the managed output atomically and restores the previous build if packaging fails.
  6. 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.yaml selects an immutable commit from dev every day at 00:00 KST. It can also be run manually.
  • .github/workflows/staging.yaml is manual and defaults to the latest dev commit.
  • A manually supplied source SHA is rejected unless it belongs to dev.
  • The same source commit is not published twice unless force is selected.
  • Release notes and channel-source.json record 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:

  1. Create a GitHub App owned by Kawaikara with repository Contents: Read and write permission.
  2. Install it with access limited to kawaikara-staging and kawaikara-nightly.
  3. Store its Client ID as the Actions repository or organization variable KAWAIKARA_RELEASE_APP_CLIENT_ID.
  4. 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 typecheck succeeds.
  • pnpm storybook:build succeeds.
  • pnpm build succeeds 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.