English · 中文 (Chinese)
Kēne (/keːne/) is a native visual novel engine built with Rust, Bevy, and wgpu. It uses a fixed 1920×1080 design space and translates external project formats through independent adapters.
The product and executable are named Kēne/keine. Compatibility identifiers
such as the keine project key, save adapter, file formats, environment
variables, and internal crate names remain stable so existing games and saves
continue to work.
- Native rendering, audio, video, UI, saves, and single-binary distribution.
- Frame-rate-independent transitions, typewriter text, timelines, and particles.
- Backgrounds, portraits, layers, filters, blend modes, camera transforms, and regional blur.
- Dialogue, narration, ruby text, choices, backlog, Auto, Skip, and rollback.
- Directory and Hexz asset overlays with development hot reload.
- WebGAL scripts and LetsGal projects compiled into one typed action model.
- Optional codec features; Ogg Opus is recommended for distributed audio.
cargo validate projects/test-project
cargo dev projects/test-projectUse cargo run -- dev projects/test-project when FFmpeg development libraries
are unavailable (the same session without video backends). The numbered visual
test is in
projects/test-project/ACCEPTANCE.md.
| Command | Purpose |
|---|---|
cargo adapters |
Enable or disable built-in adapters |
cargo validate <project> |
Validate without opening a window |
cargo compiler <project> [--output <path>] |
Compile source scripts into a program.bin artifact |
cargo package <project> [--output <dir>] |
Package an encrypted release build |
cargo dev <project> |
Run with hot reload and video |
cargo preview <project> |
Run an optimized preview |
cargo perf <project> [seconds] [cursor] [profile] |
Record a performance sample |
cargo dev <project> --sync |
Follow an open LetsGal project and step |
Invalid project paths fail immediately.
cargo compiler <project> parses and validates the project exactly like
cargo validate, then writes a versioned binary program to
.keine/compiled/program.bin (override with --output <path>). The artifact
uses a fixed envelope (magic, versions, lengths, CRC32, program fingerprint)
so release packages can skip source-script parsing at startup; the fingerprint
matches the program built from source, so saves remain compatible. Development
runs still read source scripts for diagnostics and hot reload. Use
cargo compiler preview <project> to run the compiled-loading path against any
project that has a program.bin. Release packaging runs this step automatically
and pins compiled_program: require in the packaged config.
| Input | Entry |
|---|---|
| Native / WebGAL directory | config.yaml |
| LetsGal project | project.json |
| Packaged game | game.hxz |
A directory project can combine ordered asset sources:
adapter:
asset:
- { path: ".", format: fs }
- { path: "content/shared", format: fs }
- { path: "packs/route.hxz", format: hexz }
script: webgal
store: keineLater sources override earlier files with the same logical path. LetsGal
synchronization reads open project files and .studio/state.json; Kēne
remains a separate native process and does not modify Studio.
Optional shell features are disabled by default. A native config.yaml can
enable the Extra CG/BGM gallery explicitly:
features:
extra: trueLetsGal projects use the equivalent project-level object in project.json:
{
"keine": {
"features": {
"extra": true
}
}
}Built-in adapters:
| Capability | Implementations |
|---|---|
| Assets | auto, fs, hexz |
| Scripts | webgal |
| Editor projects | letsgal |
| Packages | hexz |
| Saves | keine |
flowchart LR
P["Project<br/>WebGAL · LetsGal · Hexz"] --> L["Loader<br/>adapters · validation · resources"]
L --> C["Core<br/>Config · Action · State"]
C --> R["Runtime<br/>Bevy · rendering · UI · media"]
R --> O["Player<br/>window · audio · saves"]
External formats stop at the loader. The runtime only sees typed actions and logical resources.
flowchart LR
R["Kēne runtime<br/>src/"] --> L["keine-loader<br/>crates/loader/"]
R --> C["keine-core<br/>crates/core/"]
L --> C
core is Bevy-free, and adapter models never enter rendering or UI code.
| Path | Responsibility |
|---|---|
src/ |
Runtime, rendering, scenes, UI, media, and storage |
crates/core/ |
Typed engine model and execution state |
crates/loader/ |
Asset, script, project, and save adapters |
projects/test-project/ |
End-to-end visual acceptance |
tests/ |
Compiler, adapter, runtime, and coverage regressions |
dev/ |
Documentation, packaging, and platform scripts |
Global shortcuts use Ctrl; Esc closes or returns.
| Shortcut | Action |
|---|---|
Ctrl+A / Ctrl+K |
Auto / Skip |
Ctrl+B / Ctrl+R |
Backlog / replay voice |
Ctrl+H |
Hide or restore textbox |
Ctrl+Q / Ctrl+L |
Quick save / quick load |
Ctrl+S / Ctrl+O |
Save / load |
Ctrl+, / Ctrl+T |
Configuration / title |
hold Ctrl |
Fast-forward |
Esc |
Close or go back |
cargo build --release
cargo build --release --features video-ffmpegThe bundled Opus decoder requires CMake. Video builds require FFmpeg development libraries.
Package an encrypted Hexz game:
HEXZ_PASSWORD='your-password' \
cargo run --release --no-default-features -- package path/to/native-projectRelease packaging accepts a native project (config.yaml) or a LetsGal
project (project.json); for LetsGal, the adapter-derived config (asset
aliases, layout, styles) is materialized into config.yaml at build time.
The pipeline compiles .keine/compiled/program.bin, pins
compiled_program: require, and keeps runtime state and caches out of the
archive. Output defaults to
target/release-package (override with --output <dir>); on Windows build the
runner with --target-dir target/runner so the engine rebuild never replaces a
running executable.
The packaged engine is rebuilt per project: only the audio/video backends
detected in the content are compiled in, the hardened feature enables
anti-debugging (macOS PT_DENY_ATTACH, disabled core dumps, Windows debugger
exit), and the release profile (LTO + stripped symbols + panic=abort)
shrinks the binary from ~108 MB to ~43 MB. The HEXZ_PASSWORD key is
XOR-masked into the binary at build time, so the plaintext never appears in
the shipped string tables. Packaged builds are deliberately weak protection,
not DRM.
Create a macOS app bundle:
dev/scripts/bundle-macos.sh projects/test-projectcargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
cargo validate projects/test-project