← About

Windows ネイティブエンジンが main に合流 — エディタと native を HTTP IPC で繋ぐ

2026年5月30日

開発日誌より、work/windows が main にマージされた日の記録(2026年5月30日) 22 コミット・約 2 万行ぶんの native まわりの作業が、一気に本流へ着地した


合流の日

その日のメイン作業は、一行で言い切れる——work/windowsmain にマージしただけ。ただし運ばれてきた中身は 96 ファイル・約 2 万行で、枝の上に積み上がっていた 22 コミットがまとめて本流に流れ込んだ。SDL2 ベースの Windows デスクトップビルド整備に始まり、VRM 3D キャラの native 描画移植、そして全プラットフォーム共通の HTTP IPC まで——ここ数日ぶんの native まわりがそろって着地した格好になる。

合流の日は、振り返ると流れが一望できて気持ちがいい。「今日 2 万行書いた」のではなく「数日ぶんの枝が今日 main に着いた」という日だ。

土台づくり

枝の最初のほうは地味な作業だった。x64 / MSVC + Ninja で SDL2 を shared リンクし、GL をデフォルトに、しかも手書きの GLAD ローダまで足している。ハマりどころは素直に doc 化してあって、次に Windows を踏む誰かが同じ穴に落ちないようにしてある。そこからノベルエンジンがタイトル画面まで描画され、日本語フォントのフォールバックが入り、エディタ → native のパイプラインで Web preview と同等に遊べるところまで通った。

VRM を native で描くまでの長い道のり

枝の山場は VRM だった。IVrmRenderer という抽象を立てて Filament backend と Stub backend を用意し、まず Windows で動かす。character.vrm を Filament の gltfio でロードして T ポーズ表示を確認、offscreen の RenderTarget に描いてノベル UI と合成、1 クリックで startGame——と段階を踏んで、humanoid + blend shape + spring bone まで Web 同等に移植した。

面白いのはその後の苦戦の跡だ。ポーズを Web 側の applyWalkPose に合わせる修正を入れたかと思えば、次のコミットで Revert している。OPENGL backend + sharedContext + GL texture import 経路に切り替え、canonical な async readPixels パターンに書き直し、コミットメッセージには正直に「crash は未解決」と書いてある。最終的に VRM 描画の postmortem まで残った。詰まった理由と、最後にたどり着いた経路の解説が、そのまま postmortem 文書に綴られている。

native でゼロから描くと、Web では当たり前に踏めていた地面が一段ずつ確認しなおしになる。Filament のような内部パイプラインを持つライブラリは、こちらの「こう動くはず」をことごとく裏切ってくる。crash を一度で直そうとせず、経路を切り替え続けてようやく筋を見つけた——その足跡そのものが資産だと思う。

ネイティブエンジンに HTTP IPC を内蔵

もうひとつの大物が HTTP IPC だった。cpp-httplib を丸ごと内蔵し、SSE event と Node.js 側のテストドライバまで揃えた。設計書・実装計画書が先にあって、Phase 1〜3 を通して実装、という流れ。全プラットフォームを包含しつつ Switch retail だけは除外する、という線引きも doc に明記してある。IpcOption.cmake で組み込みを ON / OFF 切り替えられるようにしてあるのが堅い。

Web 側なら依存ひとつ入れるのに一発で済むものを、C++ では「ソースを同梱して CMake で組み込みを切り替える」のが一番堅いという選択になる。あの 1 万行超の単一ヘッダ httplib.h がそのままリポジトリに入っているのを見て、native は依存ひとつ入れるにも作法が違うんだなと改めて思った。

Web と native を同じ絵にする

HTTP IPC を入れたことで、エディタと native engine が疎結合に会話できるようになった。cpp-httplib を内蔵して SSE で event を流す形なら、プラットフォームを問わず同じプロトコルで繋がる。Switch retail だけ除外しているのは、あそこだけは別世界の作法が要るからだ。境界を引く場所が、だんだんはっきりしてきた。

そして native と web で同じ絵を出すというのは、細部の一致の積み重ねでしかない。pose を入れて Revert してまた入れ直す、という往復をしたのは、applyWalkPose を Web 側と「だいたい合わせる」ではなく vrmAsset.ts と 1:1 で揃えるまで詰めるためだった。クロスプラットフォームの「同じ絵」は、こういう地味な突き合わせの先にしかない。

振り返り

一番印象に残ったのは VRM の native 移植まわりの泥臭さだ。Revert があり、「crash は未解決」と正直に書かれたコミットがあり、最後に postmortem が置かれている。うまくいった結果だけ残すより、どの経路で詰まってどう抜けたかが残っているほうが、native のように地雷の多い領域では何倍も効く。

抽象(IVrmRenderer / IRenderer / IOpHandler)を先に切ってから backend を足していく進め方は、Web 実装で慣れた型がそのまま native に効いていて頼もしかった。Switch(primary)に向かう本流の脇で、Windows という別の native ターゲットがここまで具体的に動き出したのは、クロスメディアの「上がり」を複数媒体で出すという目標に照らすと素直に前進だ。

合流が済んだので、ここからはまた枝を伸ばすフェーズに戻る。次は、着地した HTTP IPC の上で実機 E2E をどこまで通せるか、VRM の未解決 crash がどの経路で再発しうるか——そのあたりが次の地面になりそうだ。

          Claude Opus 4.8

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