← ドキュメント一覧

エンジンの仕組み — どこでも動くスクリプトエンジン

作成日: 2026-03-06 / 更新日: 2026-06-10

kaedevn で作った作品が Web でも Android でも PC でも同じように動く秘密は、プラットフォームに依存しないスクリプトエンジンの設計にあります。約80,000行のソースコードが、この「どこでも動く」を支えています。

2つのスクリプト処理系

kaedevn には2つのスクリプト処理系があり、どちらも事前にコンパイルしてから実行します。

  • packages/compiler — KS (.ks) — スクリプトを Op[](命令配列)にコンパイル。実行時は OpRunner が命令を順に処理
  • packages/ksc-compiler(KscVM) — KSC (.ksc) — TypeScript 風の構文を型チェックし、IR(中間表現バイトコード)にコンパイルしてスタックベース VM で実行(旧 packages/interpreter の逐次解釈方式は 2026-04-29 deprecated)

どちらもスクリプトを事前に機械が読める形(KS は Op[]、KSC は IR)へ変換してから実行します。型チェックや検証を実行前に行えるのが利点です。

2つのスクリプト形式

kaedevn には用途の異なる2つのスクリプト形式があります。

KS(Kaede Script)— タグベース、約60コマンド

TyranoScript に近いシンプルな形式です。セリフや基本演出を素早く記述するのに向いています。引数はスペース区切りで、属性はクォートしません。

@bg room
@ch 赤音 smile C
#赤音
おはよう!今日もいい天気だね。@l
choice {
    "一緒に出かける" { @jump go_out }
    "家でのんびり" { @jump stay_home }
}

主な対応コマンド(全体は KS 仕様書 を参照):

  • 基本 — @bg, @ch, @ch_hide, @ch_clear, @ch_move, @overlay, @overlay_hide, @bgm, @se, @voice, @wait
  • キャラ表現(2D/Live2D/VRM 共通) — @ch_expr, @ch_lip, @ch_motion / @live2d* / @vrm*
  • 演出・エフェクト — @camera, @shake, @flash, @fade_black, @filter, @filter_mix, @color_adjust, @particle, @effect, @slash
  • 制御 — @jump, @call, @return, @call_template、選択肢 choice {}、条件 if () {}、変数 x = / += / -=
  • インライン(テキスト内) — @l(クリック待ち), @p(改ページ), @r(改行)

KSC(Kaede Script Code)— TypeScript 風、型安全

TypeScript に近い構文で、変数・条件分岐・関数定義・型チェックなどの高度なロジックが書ける形式です。

bg("room")
ch("sakura", "smile", "C")

#sakura
「おはよう!今日もいい天気だね」
#

if (affection >= 10) {
    choice {
        "一緒に出かける" { jump("go_out") }
        "デートに誘う"   { jump("date") }
    }
} else {
    choice {
        "一緒に出かける" { jump("go_out") }
        "家でのんびり"   { jump("stay_home") }
    }
}

KSC の型システム:

  • numberaffection = 5
  • stringplayerName = "太郎"
  • booleanisClear = false
  • object{hp: 100, mp: 50}
  • array[1, 2, 3]
  • unionnumber | string
  • 関数def get_rank(score) { ... }

コンパイルから実行までの流れ

KS の場合(4段階パイプライン)

.ks スクリプト
    |
    v
Tokenizer ── 字句解析(行を分類)
    |           lineClassifier で COMMAND / TEXT / LABEL を判定
    v
Parser ───── 構文解析(コマンドレジストリ参照)
    |           commandRegistry.ts が全コマンドの定義源
    v
Transformer ─ 変換・最適化
    |
    v
Finalizer ── 検証 + Op[] 出力
    |           プラットフォーム非依存の命令列
    v
OpRunner ─── 1命令ずつ実行、描画エンジンに委譲

KSC の場合(コンパイラ + スタック VM)

.ksc スクリプト
    |
    v
Lexer ────── 字句解析(Token[])
    |
    v
Parser ───── 構文解析(AST)
    |
    v
Checker ──── 静的型チェック(型不一致をコンパイル時に検出)
    |
    v
Emitter ──── IR(中間表現バイトコード)を生成
    |
    v
KscVM ────── スタックベース VM で IR を実行
    |           Web: TypeScript VM / ネイティブ: C++ 移植(ksc-vm-cpp、同一 IR を実行)
    v
HostAPI ────── 描画エンジンに命令を委譲

KSC は実行前に Checker が静的型チェックを行い、型の不一致をコンパイル時に検出します(affection = "高い" のような誤りを実行前に弾く)。コンパイル済みの IR は Web の TypeScript VM でもネイティブの C++ VM でも同一に実行されます。

重要なのは、コンパイラの出力する Op[] がプラットフォームを問わず共通 である点です。同じ命令列を Web ブラウザでも Nintendo Switch でも実行できます。

Op 型(中間表現)— エンジンの共通言語

コンパイラが出力する命令の種類は以下の通りです。

  • テキスト — TEXT_APPEND(話者名 + 本文)
  • 映像 — BG_SET, CH_SET, CH_HIDE, CH_CLEAR, CH_MOVE, OVERLAY_SET, OVERLAY_HIDE, SCREEN_FILTER, FILTER_MIX, CAMERA_SET
  • 音声 — BGM_PLAY, BGM_STOP, SE_PLAY, VOICE_PLAY
  • 制御 — CHOICE, JUMP, JUMP_IF, CALL, RETURN, VAR_SET / VAR_ADD / VAR_SUB
  • 待機 — WAIT_CLICK / WAIT_MS / WAIT_VOICE_END

スクリプトエンジンの役割

スクリプトエンジン(KS の OpRunner / KSC の KscVM)はスクリプトの「頭脳」です。以下を担当します。

  • 実行制御: コンパイル済み命令の順次実行(KS の Op[])/ コンパイル済み IR の VM 実行(KSC)
  • 変数の保持: フラグや好感度などのゲーム状態を管理(グローバル/ローカルスコープ対応)
  • フロー制御: if 分岐、ジャンプ、サブルーチン呼び出し(call / ret)、for / while ループ
  • 選択肢の処理: プレイヤーの選択を受け取り、対応するラベルへ移動

スクリプトエンジン自体は画面描画や音声再生を一切行いません。「背景を room に変えて」「BGM を再生して」といった命令を発行するだけです。実際の描画は、各プラットフォームの実装(Web なら PixiJS、Switch なら SDL2)が担当します。

IOpHandler / HostAPI — プラットフォームを繋ぐインターフェース

スクリプトエンジンと描画エンジンの間には抽象インターフェースが定義されています。KS の Op[] は IOpHandlerpackages/core)を、KSC の VM は HostAPIpackages/ksc-compiler)を通じて、描画・音声・入力を委譲します。

IOpHandler の主なメソッド:

IOpHandler
  ├── textAppend(who, text)            テキスト表示
  ├── choice(options)                  選択肢表示 → 選択結果を返す
  ├── bgSet(id, ...)                   背景変更
  ├── chSet(name, pose, pos, ...)      キャラクター表示
  ├── chHide(name, ...)                キャラクター非表示
  ├── bgmPlay(id, ...)                 BGM 再生
  ├── sePlay(id, ...)                  効果音再生
  └── waitMs / waitClick / waitVoiceEnd 待機

このインターフェースを実装するだけで、新しいプラットフォームに対応できます。実際に以下の実装が存在します。

  • WebOpHandler — Web ブラウザ(PixiJS)— 本番用
  • SDL2Engine + GLRenderer — macOS / Windows / iOS / Android — ネイティブ(OpenGL)

型チェック(コンパイル時)

Kaede Script のコード記法(KSC)は、実行前に Checker が静的型チェックを行います。

  • 型不一致の検出: number 変数に string を代入、など
  • 未定義の変数・関数・ラベルの参照を検出
  • 関数の引数の数・型の検証
  • 戻り値の型の検証

これらは IR 生成の前段(コンパイル時)に検出されるため、実行前にミスに気づけます。

// コンパイル時に型エラーを検出
affection = "高い"  // Error: number型の変数にstringを代入できません
jump(123)           // Error: jump()の引数はstringである必要があります

なぜこの設計なのか

従来のノベル系エンジンは、特定のプラットフォーム(Windows や Web)に密結合していました。kaedevn は最初から Nintendo Switch への移植を見据えて、エンジンのコア部分とプラットフォーム固有の処理を明確に分離しています。

この設計により:

  • 作者は1回書くだけ: 同じスクリプトが全プラットフォームで動く
  • 移植コストが最小: 新しいプラットフォームに対応するには IOpHandler(KS)と HostAPI(KSC)を実装するだけ
  • テストが容易: スクリプトエンジン単体でスクリプトの正しさを検証できる(画面なしで多数のユニットテストが通る)
  • 2つの入口: 初心者は KS のタグベース、上級者は KSC の TypeScript 風構文を選べる

関連ドキュメント

Ad: inContent (336x280)
Ad: stickyBottom (728x90)
kaedevn - ノベルゲームを作れるプラットフォーム