HN 日本語サマリー

← 一覧へ戻る
プログラミング

Zebkit – 組み込み可能なライブラリとしてのChromium

Zebkit – Chromium as an embeddable library (github.com)

108 pointsby Riiiiichard40 コメント

要約

Zebkitは、Chromiumのエンジンをアプリケーションに直接組み込むためのライブラリです。Electronとは異なり、アプリケーションのプロセス、ウィンドウ、ツールキットを維持したまま、Webビュー、PDFレンダリング、メディア再生などの機能を追加できます。Electronよりも軽量で高速であり、Node.jsを必要とせず、Chromiumの豊富なライブラリ群(PDFium、FFmpeg、BoringSSLなど)を直接利用可能です。Rust、Python、JavaScript向けのバインディングも提供され、PlaywrightのAPIをネイティブに実行できるため、エージェント開発にも適しています。

全文翻訳

Zebkit – 組み込み可能なライブラリとしてのChromium

[画像: zebkit]

ライブラリとしてのChrome — 軽量、高速、どこでも利用可能、そして簡単。
Linux、macOS、Windowsで単一のAPI。数行で追加できます。

[画像: crates.io] [画像: PyPI] [画像: Engine release]

はじめに

zebkitは、Chromiumのエンジンをアプリケーションにリンクできる単一のライブラリです。Blink、あらゆるJITティアを持つV8、PDFium、FFmpeg、そしてChromeを構成するその他の要素が含まれていますが、Chromeブラウザ本体やElectronのランタイムは含まれていません。あなたのアプリケーションは、C、C++、Rust、Python、またはJavaScriptで記述され、独自のウィンドウとツールキットを持ち続けます。Webが必要な場所にはzebkitビューを追加し、PDF、メディア、圧縮、暗号化が必要な場合は、CまたはRust、Python、JavaScript用のバインディング(zebkit-js、およびアプリケーション自身のページ内のzebkit.*)を介してzebkitのAPIを呼び出します。

[画像: アプリケーションは単一のライブラリzebkitをリンクし、これはChromiumのコンテンツレイヤー、Blink、V8をアプリケーションのプロセス内で実行します。ページはサンドボックス化されたヘルパープロセスで実行されます。Linux、macOS、Windowsで動作します]

  • 組み込むのであって、上に構築するのではありません。 Electronは基盤です。アプリケーションは、そのランタイム、ウィンドウ、パッケージングの上に構築されます。zebkitは一部です。アプリケーションはSQLiteを追加するようにzebkitを追加し、そのプロセス、ツールキット、配布方法を維持します。アプリケーション自身のイベントループ(zebkit_init(), zebkit_pump())内で実行され、アプリケーションのウィンドウに描画されます。描画するフレームとして、または提供されたウィンドウの子(X11ウィンドウ、NSView、またはHWND(examples/native-host))として描画され、システムダイアログのためにページが存在するウィンドウを返します。
  • 必要なものだけを取る。 ウィンドウ内またはオフスクリーンでのWebビュー(フレームは提供されます)、完全なPDF API、ページが再生するものを保存する機能、独自のURLスキーム、JavaScriptからのネイティブUI、PlaywrightのAPIとエージェント用のCDP。1つでも、すべてでも使用できます。
  • 本物のChromeエンジン。 ページはChromium 157(ユーザーエージェントとクライアントヒント、window.chrome、クリックなしでブロックされるポップアップ、デバッガがアタッチされていない状態)を認識します(docs/API.mdには、Googleのサインインなど、まだ異なる点があります)。
  • Electronより軽量。 最新のElectron 45.2.1と比較して、サイズは34%小さく、コールドスタートは2.3秒(Electronは6.6秒)、ページあたりのメモリ使用量は29%少なく、DOM、テキストレイアウト、JavaScriptレベルも同様です(ベンチマーク)。
  • Node.jsなし。 2つ目のJavaScriptランタイムや、それを通じたIPCはありません。アプリケーションはネイティブコード、またはエンジンのV8で実行されるzebkit-jsによって実行されるJavaScriptです。
  • Chromiumのライブラリはあなたのものです。 エンジン内の17個のCライブラリ(Linux、macOS、Windowsそれぞれ約7,490関数、3つすべてで7,487、残りは各システム固有)がzebkit_vendor_*としてエクスポートされています:SQLite、LevelDB、BoringSSL、zlib、Zstandard、Brotli、ICU、HarfBuzz、libxml2、libwebp、libjpeg-turbo、FFmpeg、dav1d、Opus、libvpx、FreeType、PDFium。これらを二重に配布する必要はありません。
  • PDFが組み込まれています。 ChromiumのPDFiumによる完全なAPI:レンダリングとタイル、レイアウト付きテキスト、検索、アウトライン、リンク、注釈(エディタが持つようなもの:改行、ぼかし境界線、コールアウトとリッチテキスト付きフリーテキスト、スタンプ、返信と状態、測定、XFDFとFDF)、フォーム、赤処理、ページ編集、マージ、添付ファイル、メタデータ、整合性がチェックされた署名。アプリケーション独自の注釈の種類、表示、元に戻す機能付きイベント、レンダリングレイヤー、OCR、フォント、信頼、アクションのためのフック。C、Rust、Python、JavaScriptで利用可能です。
  • 2D描画とシェーピング。 エンジンのSkia上の<zebkit/canvas.h>と、HarfBuzz上の<zebkit/text.h>を使用します。これらを別途配布する必要はありません。
  • 再生時にメディアを保存。 ページが再生するあらゆるもの(ファイル、MSE/DASH、HLS)を、再エンコードや二重ダウンロードなしで、送信されたとおりにMP4またはWebMに書き込みます(<zebkit/media.h>)。
  • バイトそのまま。 ページからアプリケーションへの呼び出しは、フレーム固有のMojoチャネルを介して行われ、大きなデータは共有メモリを介して転送されます。Base64エンコードはなく、ページのJSONはそのままの形で、小さな呼び出しではElectronのIPCと同等、大きな呼び出しではそれ以上に高速に渡されます。
  • JavaScriptからページを囲むウィンドウを生成。 zebkit.uiは、Chromiumのビューツールキットを使用してウィンドウ、プロンプト、ダイアログを描画します。シグナル、JSX、Tailwindクラス、テストとエージェントのための自動化機能を提供します。リッチUIはページであり、zebkit.uiはその周りのクロム(docs/UI.md)です。
  • PlaywrightのAPIをネイティブに。 Playwrightの全機能(ロケーター、実行可能になるまで待機するアクション、キーボード、マウス、タッチ、ルート、ダイアログ、ダウンロード、コンテキスト、ワーカー、トレース、HAR、ビデオ)が、CDPやNode.jsドライバーなしでエンジン内で実行されます。CDP経由のPlaywrightより3〜10倍高速で、クリックは33msではなく3〜5msで完了します(<zebkit/automation.h>, docs/AUTOMATION.md)。Playwright自身のクライアントは、どの言語でもchromium.connect()で変更なく接続できます。
  • エージェント向けに構築。 tools/zebkit-mcpは、オペレーターが設定した制限内で、標準入力とHTTP経由でページ、PDF、ファイル、メディア、ネイティブウィンドウをMCPツールとして提供します(docs/MCP.md)。PlaywrightのAPIやCDP(Chromium独自のDevToolsサーバー)経由でzebkitを駆動することも可能です。ヘッドレスまたはウィンドウ表示で実行できます。
  • デスクトップまで、コードからカスタマイズ可能。 ネイティブフックにより、エンジンが何を行うかをC、Rust、Python、JavaScriptで決定できます:権限、ナビゲーション、ポップアップ、ダイアログ、ダウンロード、証明書とクライアント証明書、サインイン、あらゆる段階でのネットワークリクエストとレスポンス、実行時の設定、独自のURLスキーム、ページが呼び出せるもの、ページのコードより前のスクリプト(docs/ROADMAP_HOOKS.md)。ページやエンジンがユーザーに表示したりシステムに要求したりするすべてはアプリケーションを経由します:ウィンドウフレーム(システム、オーバーレイ、またはなし、タイトルバーとしてページを使用)、メニューとコンテキストメニュー、JavaScriptダイアログとサインイン、ファイルおよびデバイス選択、画面キャプチャ、通知、トレイ、Dock、タスクバー、共有、システムのテーマ、電源、ディスプレイ(デスクトップへの統合, docs/SYSTEM_INTEGRATION.md)。
  • デフォルトで安全。 ページは、アプリケーションがビューごと、オリジンごと、および機能ごとに許可しない限り、zebkitオブジェクトを持ちません。オリジンはブラウザのものであり、ページの単語ではありません。レンダラーはサンドボックス化されたままです。ブラウザが尋ねるであろう権限は付与されません。
エンジンChromium 157.0.8103.38 (upstream.lock): コンテンツレイヤー、Blink、あらゆるJITティアを持つV8
Linuxx86-64、glibc 2.17以降(CentOS 7以降)、X11および(--ozone-platform=wayland)Wayland: libzebkit.so.1およびzebkit-helper
macOSApple silicon: Zebkit.framework、ネイティブビルドまたはLinux上でのクロスビルド(docs/MACOS.md)
Windowsx64、Windows 10以降: zebkit.dllおよびzebkit-helper.exe、Linux上でのクロスビルド(docs/WINDOWS.md)
バージョンVERSION: 0.4.0

クイックスタート

エンジンの取得

パッケージは、ライブラリ、ヘルパー、エンジンのデータ、およびinclude/を含むディレクトリです。リリースアーカイブ(GitHubのリリースからzebkit-<version>-<target>.tar.xz)を展開するか、ビルドします:

mise run r      # dist/release (Linux), dist/release-macos (macOS), dist/release-windows; 初回は数時間かかります

各アーカイブには、ライブラリの隣に、そのシステム用にビルドされ、展開した場所からすぐに実行できるツール(zebkit-run、zebkit-js、zebkit-mcp(Windowsでは.exe、そこでもサンドボックス化))も含まれています。

Xcodeが完全にインストールされたApple silicon Macでは、scripts/dist.sh releaseがエンジンをローカルのdist/releaseにビルドします。その後、scripts/example.sh macos-basicを実行して、dist/example/Zebkit Embedded Browser.app内のC埋め込みデモをビルドして起動します。

ビルドにはChromiumのツリーで約30 GBが必要です(docs/BUILD.md)。以下では、$PKGはパッケージディレクトリを表します。

既存のプログラムに追加する

zebkitはライブラリです。あなたのプログラムはmain()を維持し、それを呼び出します。これはPDFの最初のページをPNGにレンダリングし、そのテキストを読み取ります。PDFiumとzebkit内の画像エンコーダーを使用し、他にインストールする必要はありません:

#include <stdio.h>
#include <zebkit/pdf.h>
#include <zebkit/services.h>

/* あなたのプログラム、あなたのmain(): zebkitは単に呼び出されるライブラリです。 */
int main(int argc, char **argv) {
    char *error = NULL;
    zebkit_pdf *pdf = zebkit_pdf_open_file(argv[1], NULL, &error);
    if (!pdf) {
        fprintf(stderr, "%s\n", error);
        return 1;
    }

    /* 最初のページを2倍のサイズでPNGとして出力。 */
    zebkit_pdf_render_options options = {.scale = 2, .background = 0xffffffff};
    int width, height;
    uint8_t *rgba = zebkit_pdf_render(pdf, 0, &options, &width, &height, &error);
    size_t size;
    uint8_t *png = zebkit_image_encode(ZEBKIT_IMAGE_PNG, rgba, width, height, 0, &size, &error);
    fwrite(png, 1, size, fopen("page1.png", "wb"));

    /* そしてそのテキスト。 */
    char *text = zebkit_pdf_text(pdf, 0, &error);
    printf("%d pages; page 1 says: %.80s\n", zebkit_pdf_page_count(pdf), text);

    zebkit_free(text), zebkit_free(png), zebkit_free(rgba);
    zebkit_pdf_close(pdf);
    return 0;
}
cc thumb.c -I$PKG/include -L$PKG -l:libzebkit.so.1 -Wl,-rpath,$PKG -o thumb   # Linux
cc thumb.c -I$PKG/include -F$PKG -framework Zebkit -Wl,-rpath,$PKG -o thumb   # macOS
./thumb report.pdf     # 2 pages; page 1 says: Quarterly report ...

PDF API、圧縮、暗号化、URL、画像コーデック、ICU、およびエンジン内のライブラリ(zebkit_vendor_*、FFmpegを含む)はエンジンループを必要としません(docs/API.md)。ネットワークスタックを介したHTTPとWebページのみがエンジンループを必要とします。

Webビューの追加

Webページはエンジンの実行を必要とします。ここではエンジンがループを実行します。プログラムはzebkit_main()でそれを開始し、コールバックで作業します。独自のループを持つプログラム(GTK、Qt、AppKit、winit)は、zebkit_init()で開始し、zebkit_pump()を呼び出します(examples/native-host)。

#include <stdio.h>
#include <zebkit/zebkit.h>

static void printed(zebkit_view *view, const char *json, const char *error, void *data) {
    printf("%s\n", json ? json : error);
    zebkit_quit();
}

static void loaded(zebkit_view *view, zebkit_load_event event, const char *url, void *data) {
    if (event == ZEBKIT_LOAD_FINISHED)
        zebkit_view_evaluate(view, "document.title", printed, NULL);
}

static void ready(void *data) {
    zebkit_view *view = zebkit_view_new("https://example.com/", 1024, 768);
    zebkit_view_on_load(view, loaded, NULL);
}

int main(int argc, char **argv) {
    return zebkit_main(argc, argv, ready, NULL);
}
cc app.c -I$PKG/include -L$PKG -l:libzebkit.so.1 -Wl,-rpath,$PKG -o app   # Linux
cc app.c -I$PKG/include -F$PKG -framework Zebkit -Wl,-rpath,$PKG -o app   # macOS
clang-cl /MT app.c /I%PKG%\include %PKG%\zebkit.dll.lib %PKG%\zebkit_sandbox.lib   # Windows
./app --remote-debugging-port=9222     # CDP for Puppeteer and Playwrightを使用

Windowsでは、実行可能ファイルがChromiumのサンドボックスに参加します。zebkit_sandbox.libをリンクし、main()の最初にzebkit_win_startup()を呼び出します(docs/WINDOWS.md)。

特権のないユーザー名前空間がない場合、エンジンは起動を拒否し、その理由を説明します。ヘルパーをインストールするか、独自のコンテナ内で--no-sandboxを追加してください(docs/SANDBOX.md)。

ページとアプリケーション

アプリケーションは独自のページをスキームから提供し、呼び出し可能な関数を与えます。ページは、許可されない限りzebkitの何ものも持ちません。

/* ページは`zebkit.app.greet("Ada")`を呼び出します。 */
static void greet(zebkit_view *view, const char *origin, const char *args_json,
                  zebkit_call *call, void *data) {
    char answer[256];
    snprintf(answer, sizeof answer, "{\"hello\": %s}", args_json);
    zebkit_call_resolve(call, answer);
}

/* `./ui`からの`app://main/...`、メディアの範囲内。実際のハンドラは`..`を拒否します。 */
static void serve(zebkit_request *request, void *data) {
    char path[1024];
    snprintf(path, sizeof path, "ui%s", zebkit_request_url(request) + sizeof "app://main" - 1);
    zebkit_request_respond_file(request, path, NULL);
}

static void closed(zebkit_view *view, void *data) { zebkit_quit(); }

static void ready(void *data) {
    zebkit_view *view = zebkit_view_new("app://main/index.html", 1024, 768);
    zebkit_view_grant(view, "app://main", ZEBKIT_ALLOW_APP | ZEBKIT_ALLOW_PDF, NULL);
    zebkit_view_bind(view, "greet", greet, NULL);
    zebkit_view_on_close(view, closed, NULL);
}

int main(int argc, char **argv) {
    zebkit_scheme_register("app", ZEBKIT_SCHEME_STANDARD | ZEBKIT_SCHEME_SECURE | ZEBKIT_SCHEME_FETCH);
    zebkit_scheme_handle("app", serve, NULL);
    return zebkit_main(argc, argv, ready, NULL);
}

ページ内では、すべての呼び出しはPromiseであり、バイトはUint8Arrayです:

const reply = await zebkit.app.greet('Ada');            // アプリケーションの関数
const pdf = await zebkit.pdf.open(await (await fetch('report.pdf')).bytes());
const rgba = await pdf.render(0, {scale: 2});           // ページをピクセルとして
const hits = await pdf.search('revenue');
const packed = await zebkit.compress('zstd', bytes, 19);
const hash = await zebkit.crypto.digest('SHA-256', 'abc');
デスクトップへの統合

エンジンがユーザーに表示したり、システムに要求したりする各項目には、機能するデフォルトと、それを置き換えるアプリケーションの関数があります。アプリケーションが決定できることなしにシステムに到達するものはありません。関数がない場合、ページは慎重なブラウザが提供するものを受け取りますが、ブラウザが尋ねる場所では何も受け取りません。

import zebkit

zebkit.scheme_register("app")   # Cの例のようにscheme_handle()で提供されます
zebkit.init(["app"])
# ページはタイトルバーです。ウィンドウのボタンがその上にあり、CSSでドラッグされます。
view = zebkit.View("app://main/index.html", 1000, 700, options={
    "frame": "overlay", "controls": {"height": 40, "color": "#1b1d2a", "symbolColor": "#ffffff"},
    "dragRegions": {"source": "css", "origins": ["app://main"]}})

# アプリケーションのメニューバー(macOS)とキー、状態がその場で変化します。
zebkit.app_set_menu([{"title": "File", "items": [{"title": "Autosave", "id": "autosave", "checked": True}]}],
                    lambda item: zebkit.app_update_menu_item(item, checked=False))

# トレイアイコン、Dockまたはタスクバーのバッジ、およびページの通知をアプリケーションのものとして扱います。
tray = zebkit.Tray(open("icon.png", "rb").read(), "My application")
zebkit.app_set_badge("3")
zebkit.on_notification(lambda event: print("show in my own UI:", event))

# ページが要求するもの:USBデバイス、キャプチャする画面、色、共有。
view.on_device_chooser(lambda request: request.respond(request.metadata["devices"][0]["id"]))
view.on_media_access(lambda request: request.respond(True, None, "view"))
view.on_share(lambda request: request.respond(True))

# システム:テーマとその変更、セッションのロック、画面。
zebkit.on_environment_changed(lambda env: print("dark" if env["colorScheme"] == "dark" else "light"))
zebkit.on_power_event(lambda event: print(event["event"]))   # suspend, resume, lock, unlock
print(zebkit.displays())
デフォルトアプリケーションのもの
ウィンドウフレームシステムのものoverlay(Window Controls Overlay)またはnone、タイトル、色、ドラッグ領域、状態、アクション
メニューmacOSのメニューバー、デフォルトのコンテキストメニューIDによる状態を持つ項目。コンテキストメニューは置き換え、拡張、または実行される
ダイアログシステムのアラート。ウィンドウがある場合のエンジンプロンプトとサインインzebkit_view_on_dialog, on_http_auth, on_client_certificate, アイサプライ
ファイルとデバイスシステムのファイルダイアログ。デバイスなしファイル選択ダイアログとファイルシステムアクセス。WebUSB、WebHID、Web Serial選択ダイアログ
キャプチャとメディア権限によるカメラとマイク。画面なしgetDisplayMedia()のソース:ビュー自体または画面
通知未決定。その後、システムの独自サービスアプリケーションのUIに表示され、クリックとクローズはページに戻る
デスクトップなしトレイ、Dock/タスクバーのバッジ、進捗と注意、Dockメニュー、Web共有、URLやフォルダのオープン
システムライトなページシステムのダークモードとコントラストをライブで追跡。電源、ロック、ディスプレイイベント。スリープしないようにする

docs/SYSTEM_INTEGRATION.mdには、各サーフェス、そのデフォルト、各システムでのステータス、およびその理由が記載されています。docs/API.mdには4つの言語での呼び出しが記載されています。examples/custom-titlebarは、タイトルバーがページであるウィンドウです。

Rust

crates.ioのzebkitと、エンジンをプログラムの隣に配置するためのzebkit-build。ビルドはシステム用のエンジンを一度ダウンロードし、そのSHA-256をチェックします。

[dependencies]
zebkit = "0.4.0"

[build-dependencies]
zebkit-build = "0.4.0"
// build.rs: エンジンを実行可能ファイルの隣に配置します
fn main() { zebkit_build::bundle(); }

// main.rs
fn main() {
    std::process::exit(zebkit::run(|| {
        let view = zebkit::View::new(Some("https://example.com/"), 1024, 768);
        view.grant("https://example.com", zebkit::Allow::APP, None);
        view.bind("greet", |call| {
            let answer = format!("\"hello, {}\"", call.args_json());
            call.resolve(&answer)
        });
        view.on_close(zebkit::quit);
    }));
}

ZEBKIT_DIRはビルドにパッケージを指し示します(bindings/rust/README.md)。

Python

PyPIのzebkitはバインディングです。エンジンは、同じバージョンのリリースからシステム用のアーカイブであり、ZEBKIT_DIRがそれを指し示します:

pip install zebkit
export ZEBKIT_DIR=/path/to/zebkit-0.4.0-x86_64-unknown-linux-gnu
import zebkit                      # ctypes上の純粋なPython: コンパイル不要

def ready():
    view = zebkit.View("https://example.com/")
    view.grant("https://example.com", zebkit.ALLOW_APP)
    view.bind("greet", lambda name, origin: f"hello, {name}")

zebkit.main(ready)                 # エンジンは$ZEBKIT_DIRで見つかります
JavaScript、Node.jsなし

zebkit-jsは、エンジンのV8上でESモジュールを実行し、JavaScriptで書かれたアプリケーション、ビュー、同じAPI、ネイティブウィンドウを提供します:

// zebkit-js main.mjs
const view = new zebkit.View('app://main/index.html', {width: 1024, height: 768});
view.grant('app://main', ['app', 'pdf']);
view.bind('save', async (name, text) => {
  await zebkit.fs.writeFile(`${zebkit.args[0]}/${name}`, text);
  return {saved: true};
});
view.on('close', () => zebkit.quit());
// zebkit-js examples/ui/todo.mjs: ネイティブウィジェットのウィンドウで、
// Tailwindクラスでスタイル設定され、シグナルで最新の状態に保たれます(抜粋)
const {h, signal, computed, For, window} = zebkit.ui;
const [tasks, setTasks] = signal([]);
const done = computed(() => tasks().filter((t) => t.done).length);

const Task = (task) =>
  h('view', {class: 'flex-row items-center gap-3 p-3 rounded-xl bg-[#141a2e]'}, 
    h('button', {class: 'w-8 h-8 p-0 rounded-full bg-[#7c5cff] text-white',
                 onClick: () => toggle(task)}, task.done ? '✓' : ''),
    h('text', {class: 'grow text-[#e6e8f2]'}, task.text));

window({title: 'Today', width: 460, height: 680}, () =>
  h('view', {class: 'flex-col gap-4 p-6 bg-[#0b1020]'}, 
    h('text', {class: 'text-3xl font-bold text-white'}, 'Ship something great'),
    h('text', {class: 'text-sm text-[#8a91aa]'}, () => `${done()} of ${tasks().length} done`),
    h(For, {each: tasks}, Task)));

[画像: examples/ui/todo.mjs]

エージェント

PlaywrightのAPIはエンジン内で実行されます(docs/AUTOMATION.md)。Playwrightプロトコルのすべてのコマンドが、アプリケーションのプロセス内で、Node.jsやCDPなしで実行されます。Cからは単一の呼び出しzebkit_automation_call(view, "Frame.click", "{\"selector\": \"#go\"}", done, data)です。PythonではPlaywrightの名前で利用できます:

import zebkit
from zebkit.automation import Page, expect, run

async def test():
    page = Page()
    await page.goto("https://example.com/")
    await expect(page).to_have_title("Example Domain")
    await expect(page.get_by_text("documentation examples")).to_be_visible()
    await page.screenshot(path="example.png")
    zebkit.quit()

zebkit.main(lambda: run(test()), ["python", "--headless"])

Playwright自身のクライアント、テストランナー、その他の言語は、chromium.connect()を使用して、変更なくエンジンのPlaywrightエンドポイントに接続します:

tools/zebkit-run --headless --playwright-port=0   # "Playwright listening on ws://127.0.0.1:<port>/<token>"と表示されます
const browser = await chromium.connect('ws://127.0.0.1:<port>/<token>');
const page = await (await browser.newContext()).newPage();

エージェントとCDPを話すツールは、Chromeを駆動するのと同じようにzebkitを駆動します:

tools/zebkit-run --headless --remote-debugging-port=9222 https://example.com/

任意のCDPクライアントはhttp://127.0.0.1:9222に接続できます。

MCPクライアントは、tools/zebkit-mcp(別のプログラム)からエンジンの機能をツールとして取得します。ファイルアクセスとオリジンは、オペレーターが付与するまで拒否されます(docs/MCP.md):

ZEBKIT_DIR=<package> cargo build --release --manifest-path tools/zebkit-mcp/Cargo.toml   # またはアーカイブのもの
zebkit-mcp --allow-origin https://example.com --allow-write ~/agent-files   # 標準入出力で
zebkit-mcp --http 8931 --allow-origin '*'                                   # 127.0.0.1で、トークン付き
例
mise example:linux:basic    # examples/window.c: ブラウザウィンドウ
mise example:rust:window    # 同じものをRustで
mise example:ffmpeg         # examples/ffmpeg.cpp: エンジン内のライブラリ
(cd examples/gpui-browser && cargo run --release)   # GPUI-KITでのタブ付きブラウザ

ベンチマーク

最新の安定版Electron 45.2.1(Chromium 156)と比較して、同じ方法で測定されました。1つのハーネス、同じページ、同じことを行う2つの薄いホスト、カウントされたすべてのプロセス、順番に実行される5〜11回の実行の中央値、Linux x86-64、2026-11-06および07(scripts/electron-compare.sh, docs/reports/electron-compare.md)。

zebkit 0.2.0Electron 45.2.1
アプリケーションが配布するもの、非圧縮 / .tar.xz171.2 / 59.4 MiB260.5 / 87.1 MiB34%小さい
スタート、コールド、初回ペイントまで2.3 s6.6 s66%少ない
スタート、ウォーム、初回ペイントまで116 ms236 ms51%少ない
メモリ、空のページ179 MB250 MB29%少ない
ページからホストへの呼び出しと戻り、1 MiB / 16 MiB3.3 / 58 ms4.3 / 66 ms23% / 12%少ない
DOM、20,000要素の作成とレイアウト280 ms278 ms同等
JavaScriptとDOM、10のワークロード1139 ms1193 ms同等
テキストレイアウト、本の章8.1 ms7.6 ms同等、ノイズの範囲内
各ビューアに756ページのPDFを表示:CPU / メモリ0.75 s / 261 MB1.6 s / 399 MB53% / 35%少ない
10の人気のサイト:CPU負荷 / メモリ21.7 s / 4756 MB25.2 s / 5060 MB14% / 6%少ない
プロセス、1ページ761つ多い:ストレージが独自のプロセスでサンドボックス化されている、Chromeのように
  • サイズ。 zebkitはアプリケーションが使用するWebプラットフォーム全体を保持します:HTML、CSS、あらゆるJITティアを持つJavaScript、WebAssembly、WebGL、H.264とAACを持つメディア、HTTP/3、PDF。
  • 速度。 Chrome独自のプロファイルガイド付き最適化は、zebkitがChromeと同様にCFIでビルドされているためBlinkに到達します。速度の変更は、サイズよりも利得がある場合にのみ保持されます(docs/SIZE_AND_SPEED.md)。
  • Electronが優れている点: ページあたりのプロセスが1つ少なく、10のサイトのうち2つ(YouTubeとThe Verge)でメモリ使用量が少ない。これらは広告とビデオが決定要因です。
  • 各数値の算出方法:docs/SIZE_AND_SPEED.md。

同じPlaywrightコマンドを3つの方法で実行した場合の中央値(docs/reports/automation-bench.md, scripts/automation-bench.sh):

インプロセスでのzebkit APIzebkitに接続されたあなたのPlaywrightスクリプトChrome 156でのPlaywright
locator.click()2.0 ms3.5 ms33.3 ms
locator.fill()2.1 ms2.0 ms2.9 ms
locator.press('Enter')0.59 ms0.98 ms2.6 ms
locator.textContent()0.23 ms0.70 ms0.81 ms
200個のallTextContents()0.34 ms1.9 ms1.9 ms
page.goto()11.2 ms13.0 ms18.2 ms
page.screenshot()12.4 ms16.7 ms33.8 ms
page.screenshot({type: 'jpeg'})13.9 ms14.4 ms32.9 ms
スクリーンショットのピクセル、エンコードなし9.3 ms
  • インプロセスでのzebkit API: あなたのプログラムは<zebkit/automation.h>、Pythonのzebkit.automation、またはRustのzebkit::automationを通じてコマンドを呼び出します。これはエンジン内で実行され、Node.jsやプロトコルは不要です。
  • zebkitに接続されたあなたのPlaywrightスクリプト: Playwright自身のNode.jsクライアントは、chromium.connect()を使用してzebkitのエンドポイントに接続すれば、変更なく動作します。そのテストスイート(v1.64.1)は、Chromeが4,196テスト中4,046テストをパスするのに対し、ここで4,046テストをパスします(docs/AUTOMATION.md、セクション7)。
  • ChromeでのPlaywright: 通常のPlaywright、CDP経由。
  • なぜ速いのか: レンダラー内での単一の呼び出しで、PlaywrightサーバーがCDP経由で複数のラウンドトリップを行う必要がなく、プロセス間のJSON転送がなく、Node.jsプロセスも不要です(Playwright単独で175 MiBに達しました)。また、クリックのチェックが待機するフレームは、ディスプレイのないページで60 Hzではなく一度に作成されます。
  • スクリーンショットは2.7倍高速: 次の60 Hzティックではなく一度に作成される新しいフレームを取得し、PNGはレベル1のUpフィルターで圧縮されます(Chromeのデフォルトレベルが13 msかかるのに対し59 KB(このページでは40 KB)で2 ms)。画像の共有メモリは単一の呼び出しで作成され、ページフォールトごとに1つずつではありません。12 msの残りは、ページのフレーム(4 ms)、コンポジターからの画像のコピー(4 ms)、およびエンコード(4 ms)です。エンコードなしのピクセル自体(zebkit_automation_screenshot_pixels()、zebkit独自)は9 msかかります。CDP経由では、zebkitはChromeと同じことを行います:60 Hzでのフレーム、ChromeのPNG。

リファレンス

ドキュメント
ドキュメント内容
docs/API.mdアプリケーションが呼び出せるすべて(C、Rust、Python、JavaScript)
docs/BUILD.mdChromiumの取得、ビルド、パッケージング、テスト、測定、リリース。プロファイルとパッチ
docs/ARCHITECTURE.mdエンジンの構造と、このリポジトリの各部分の説明
docs/AUTOMATION.mdCDPなしのPlaywright API:Playwrightの仕組み、zebkitの代替手段、エンドポイント、コスト
docs/MCP.mdtools/zebkit-mcp:エージェント向けのMCPツールとしてのエンジン、その制限、脆弱性
docs/SIZE_AND_SPEED.mdサイズの内訳、削減・維持されたもの、速度に対するコンパイラの影響、Electronのベースライン
docs/MACOS.mdmacOSフレームワーク、ネイティブビルドとクロスビルド
docs/WINDOWS.mdWindows DLL、そのサンドボックス、Linux上でのクロスビルド、ポートのステータス
docs/SANDBOX.md各システムでのサンドボックス、およびサンドボックスなしでの実行
docs/ROADMAP.mdライブラリとエンジン:要件、完了したこと、今後の予定
docs/ROADMAP_HOOKS.mdフック:アプリケーションがネイティブコードからエンジンの動作を決定する方法
docs/UI.mdzebkit.ui:エンジンの独自の小規模UI、その目的とそうでないもの
bindings/rust/README.mdRustクレート
docs/releases/各リリース:内容、テスト済み、不足しているもの
docs/reports/スクリプトによって再生成されるサイズレポート
リポジトリ
パス内容
upstream.lockビルドされたChromiumリリース、ピン留めされたdepot_tools、比較対象のElectronリリース
profiles/GN引数としてのビルドフレーバー:slim.gn(製品)、slim-macos.gn、slim-windows.gn、baseline.gn(Chromiumのデフォルト)
patches/patches/seriesの順序で適用されるChromiumへの変更
src/engine///zebkit/engineとしてChromiumにリンクされるzebkit独自のコード:ライブラリ、C API、ヘッダー
src/ffmpeg/scripts/ffmpeg-config.shからのzebkitのFFmpeg設定
bindings/rust/, bindings/python/RustクレートとPythonバインディング
tools/zebkit-run(ページを開く、CDPまたはPlaywrightのエンドポイントを提供する)、zebkit-js(JavaScriptでのアプリケーション)、zebkit-mcp(MCPツールとしてのエンジン)
tests/パッケージに対してAPIのすべてのレイヤーをテストするプログラム。速度ワークロード
examples/Cでのブラウザウィンドウ、zebkit.ui、エンジン内のライブラリ、Electronのベースライン
scripts/すべてのステップ、各スクリプト1つ。mise tasksはショートフォームをリストします

upstream/(Chromiumのツリー、約30 GB)、out/、dist/、.cache/は生成されるもので、追跡されません。

zebkitはChromiumに小さなパッチセット(patches/)を追加し、ソースからビルドされます。アプリケーションが必要とするものがChromiumに欠けている場合、zebkitはそれを回避するのではなく、Chromiumにパッチを適用します(docs/BUILD.md)。