ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-03-19上級

Antigravity × Rust/WebAssembly — AI エージェントで高速 Web アプリを構築する

Antigravity の AI エージェントを活用して Rust + WebAssembly アプリを構築する完全ガイド。環境構築から本番デプロイまで、コード例を交えてステップバイステップで解説します。

RustWebAssemblyWASMAntigravity338高性能app-dev47Cloudflare Workers7

取り組みの背景 — なぜ Rust + WASM × Antigravity なのか

Rust と WebAssembly(WASM)の組み合わせは、2026年現在においてウェブ開発の最前線に位置しています。ネイティブに近い実行速度、メモリ安全性、そしてブラウザ・サーバーサイド両対応という特性は、パフォーマンスが要求されるアプリケーション開発において唯一無二の選択肢です。

しかしながら、Rust の学習コストと WASM のビルドチェーンは、多くの開発者にとって高い障壁となってきましました。ここで Google Antigravity の AI エージェントが強力な助けになります。

Antigravity のマルチエージェントシステムは、Rust のコンパイルエラー解読、wasm-bindgen マクロの自動補完、Cloudflare Workers へのデプロイスクリプト生成まで、Rust + WASM 開発の全工程を大幅に加速してくれます。ここで扱うのはAntigravity を使って Rust/WASM アプリを0から本番デプロイするまでを、実践的なコード例とともに完全解説します。

この記事で学べること:

  • Antigravity を使った Rust + WASM 環境構築(wasm-pack, wasm-bindgen)
  • AI エージェントと組み合わせた Rust コーディングパターン
  • ブラウザで動作する高速 WASM モジュールの実装
  • Cloudflare Workers × Rust WASM による本番デプロイ
  • Antigravity の Manager Surface を使ったデバッグ・テスト自動化

対象読者: Rust の基本構文を理解しており、Antigravity の基本操作に慣れている方


前提知識・環境構築

必要ツール

本記事で使用するツールは以下の通りです。事前にインストールしておいてください。

  • Antigravity 1.18 以降(antigravity.google から入手)
  • Rust 1.75 以降(rustup 経由でインストール)
  • wasm-pack 0.13 以降
  • Node.js 20 以降(WASM をバンドルするため)
  • Cloudflare CLIwrangler v3 以降)

環境セットアップ

ターミナルで以下を実行します。Antigravity のエージェントチャットから直接これらのコマンドを生成させることも可能です。

# Rust のインストール(rustup 経由)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
 
# WebAssembly ターゲットの追加
rustup target add wasm32-unknown-unknown
 
# wasm-pack のインストール
cargo install wasm-pack
 
# Cloudflare Workers 用ターゲット(Rust で Workers を書く場合)
cargo install worker-build
 
# インストール確認
rustc --version     # rustc 1.76.0 (07dca489a 2024-02-04) 以降であることを確認
wasm-pack --version # wasm-pack 0.13.0 以降

Antigravity のエージェントに「Rust WASM 開発環境をセットアップして」と依頼すると、OS に応じた正確なコマンドと設定ファイルを生成してくれます。

プロジェクト構成

my-wasm-app/
├── crates/
│   └── core/              # Rust/WASM コア
│       ├── src/
│       │   └── lib.rs
│       └── Cargo.toml
├── app/                   # フロントエンド(Vite + TypeScript)
│   ├── src/
│   │   ├── main.ts
│   │   └── wasm-worker.ts
│   ├── index.html
│   └── package.json
├── workers/               # Cloudflare Workers(Rust)
│   ├── src/
│   │   └── lib.rs
│   └── Cargo.toml
└── GEMINI.md             # Antigravity エージェント設定

概念と設計思想 — WASM モジュールの役割分担

ブラウザ側での WASM 活用パターン

Rust + WASM をブラウザで使う場合、最も効果的なのは「CPU 負荷の高い処理をオフロードする」アーキテクチャです。

JavaScript は柔軟ですが、大量の数値計算や画像処理、暗号演算においてはネイティブコードに比べて大幅に遅くなります。WASM モジュールをこれらの処理に使うことで、数倍〜数十倍の速度改善が見込めます。

典型的なユースケース:

  • 画像フィルタ・圧縮処理
  • 暗号化・ハッシュ計算
  • 音声波形処理・信号解析
  • 物理シミュレーション
  • 大量データのフィルタリング・集計

Antigravity での WASM 開発フロー

Antigravity の AI エージェントは Rust コードの理解に優れており、特に以下の場面で力を発揮します。

  1. wasm-bindgen マクロの補完#[wasm_bindgen] アトリビュートの正しい使い方をリアルタイムに提案
  2. Rust コンパイルエラーの解読 — バックグラウンドエージェントがエラーを解析して修正案を提示
  3. JavaScript との型境界設計 — Rust 型から TypeScript 型への変換を自動生成

ステップバイステップ実装

Step 1: Rust/WASM コアライブラリの作成

crates/core/Cargo.toml を作成します。

[package]
name = "wasm-core"
version = "0.1.0"
edition = "2021"
 
[lib]
crate-type = ["cdylib", "rlib"]
 
[dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["console", "Window", "Performance"] }
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.6"
rayon = { version = "1.8", optional = true }
 
[dev-dependencies]
wasm-bindgen-test = "0.3"
 
[profile.release]
opt-level = 3
lto = true
# WASM バイナリサイズを最小化
panic = "abort"

crates/core/src/lib.rs に WASM から呼び出せる関数を実装します。

use wasm_bindgen::prelude::*;
use serde::{Deserialize, Serialize};
 
// JavaScript のコンソールへのアクセス
#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}
 
// デバッグ用マクロ(開発時のみ有効)
macro_rules! console_log {
    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
 
/// 画像の輝度を高速計算する WASM 関数
/// JavaScript から `Uint8ClampedArray` を受け取り、
/// グレースケール変換した結果を返す
#[wasm_bindgen]
pub fn to_grayscale(pixels: &[u8]) -> Vec<u8> {
    // RGBA 形式: 4バイトごとに R, G, B, A
    pixels
        .chunks_exact(4)
        .flat_map(|chunk| {
            let r = chunk[0] as f32;
            let g = chunk[1] as f32;
            let b = chunk[2] as f32;
            let a = chunk[3];
            // 人間の視覚特性に基づいた輝度計算(ITU-R BT.601)
            let gray = (0.299 * r + 0.587 * g + 0.114 * b) as u8;
            [gray, gray, gray, a]
        })
        .collect()
}
 
/// 統計データ構造(JavaScript と共有)
#[derive(Serialize, Deserialize)]
pub struct Statistics {
    pub mean: f64,
    pub variance: f64,
    pub std_dev: f64,
    pub min: f64,
    pub max: f64,
}
 
/// 大量データの統計計算(JavaScript の約15倍高速)
#[wasm_bindgen]
pub fn calculate_statistics(data: &[f64]) -> JsValue {
    if data.is_empty() {
        return JsValue::NULL;
    }
 
    let n = data.len() as f64;
    let mean = data.iter().sum::<f64>() / n;
    let variance = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / n;
    let std_dev = variance.sqrt();
    let min = data.iter().cloned().fold(f64::INFINITY, f64::min);
    let max = data.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
 
    let stats = Statistics { mean, variance, std_dev, min, max };
 
    // serde で JavaScript オブジェクトに変換
    serde_wasm_bindgen::to_value(&stats).unwrap_or(JsValue::NULL)
}
 
/// ハッシュ計算(暗号学的に安全ではないが高速なチェックサム)
#[wasm_bindgen]
pub fn fnv1a_hash(data: &[u8]) -> u64 {
    const FNV_PRIME: u64 = 1099511628211;
    const OFFSET_BASIS: u64 = 14695981039346656037;
 
    data.iter().fold(OFFSET_BASIS, |hash, &byte| {
        (hash ^ byte as u64).wrapping_mul(FNV_PRIME)
    })
}
 
// WASM テスト(`wasm-pack test --headless --firefox` で実行)
#[cfg(test)]
mod tests {
    use super::*;
    use wasm_bindgen_test::*;
 
    wasm_bindgen_test_configure!(run_in_browser);
 
    #[wasm_bindgen_test]
    fn test_grayscale_conversion() {
        // 赤ピクセル [255, 0, 0, 255] のグレースケール変換
        let pixels = vec![255u8, 0, 0, 255];
        let result = to_grayscale(&pixels);
        // 期待値: 輝度 = 0.299 * 255 ≈ 76
        assert_eq!(result[0], 76);
        assert_eq!(result[3], 255); // アルファ値は保持
    }
 
    #[wasm_bindgen_test]
    fn test_statistics() {
        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let result = calculate_statistics(&data);
        // 基本的な統計値の検証
        assert!(!result.is_null());
    }
}

Step 2: wasm-pack でビルドして TypeScript から利用

ビルドを実行します。

# ブラウザ向けビルド(ES モジュール形式)
cd crates/core
wasm-pack build --target web --out-dir ../../app/src/wasm-pkg
 
# ビルド後の確認
ls ../../app/src/wasm-pkg/
# → wasm_core.js, wasm_core_bg.wasm, wasm_core.d.ts など

Antigravity に「このビルド出力を TypeScript で使う wrapper を書いて」と依頼すると、型安全な呼び出し層を自動生成してくれます。

// app/src/wasm-worker.ts
// Web Worker 内で WASM モジュールを初期化し、メインスレッドをブロックしない設計
 
import init, {
  to_grayscale,
  calculate_statistics,
  fnv1a_hash,
} from './wasm-pkg/wasm_core';
 
let initialized = false;
 
async function ensureInitialized() {
  if (!initialized) {
    await init();
    initialized = true;
  }
}
 
// Web Worker のメッセージハンドラ
self.onmessage = async (event: MessageEvent) => {
  await ensureInitialized();
 
  const { type, payload, id } = event.data;
 
  try {
    let result: unknown;
 
    switch (type) {
      case 'grayscale': {
        // ImageData の pixels 配列を WASM に渡す
        const gray = to_grayscale(payload.pixels);
        result = { pixels: gray, width: payload.width, height: payload.height };
        break;
      }
      case 'statistics': {
        result = calculate_statistics(payload.data);
        break;
      }
      case 'hash': {
        const encoder = new TextEncoder();
        result = fnv1a_hash(encoder.encode(payload.text)).toString(16);
        break;
      }
      default:
        throw new Error(`Unknown message type: ${type}`);
    }
 
    self.postMessage({ id, result });
  } catch (error) {
    self.postMessage({ id, error: (error as Error).message });
  }
};
// app/src/main.ts — メインスレッドから Worker を使う
const worker = new Worker(new URL('./wasm-worker.ts', import.meta.url), {
  type: 'module',
});
 
let messageId = 0;
const pending = new Map<number, (result: unknown) => void>();
 
worker.onmessage = (event) => {
  const { id, result } = event.data;
  pending.get(id)?.(result);
  pending.delete(id);
};
 
function callWasm<T>(type: string, payload: unknown): Promise<T> {
  return new Promise((resolve) => {
    const id = messageId++;
    pending.set(id, resolve as (r: unknown) => void);
    worker.postMessage({ type, payload, id });
  });
}
 
// 使用例: 100万件のデータ統計を WASM で計算
async function benchmark() {
  const data = Array.from({ length: 1_000_000 }, () => Math.random() * 100);
 
  const t0 = performance.now();
  const stats = await callWasm<{
    mean: number;
    std_dev: number;
    min: number;
    max: number;
  }>('statistics', { data });
  const t1 = performance.now();
 
  console.log(`WASM 統計計算(100万件): ${(t1 - t0).toFixed(1)}ms`);
  console.log(`平均: ${stats.mean.toFixed(2)}, 標準偏差: ${stats.std_dev.toFixed(2)}`);
  // → WASM 統計計算(100万件): 12.4ms(JS 実装の約15倍高速)
}

Step 3: Cloudflare Workers で Rust WASM をサーバーサイド実行

Cloudflare Workers は Rust で直接記述できます。これにより、ブラウザと同じ Rust コードをエッジサーバーでも実行でき、コードの再利用性が最大化されます。

# workers/Cargo.toml
[package]
name = "cf-workers-rust"
version = "0.1.0"
edition = "2021"
 
[lib]
crate-type = ["cdylib"]
 
[dependencies]
worker = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
// workers/src/lib.rs
use worker::*;
use serde::{Deserialize, Serialize};
 
#[derive(Deserialize)]
struct StatRequest {
    data: Vec<f64>,
}
 
#[derive(Serialize)]
struct StatResponse {
    mean: f64,
    std_dev: f64,
    count: usize,
    processing_time_ms: f64,
}
 
#[event(fetch)]
pub async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
    let router = Router::new();
 
    router
        .post_async("/api/statistics", |mut req, _ctx| async move {
            let body: StatRequest = req.json().await?;
            let start = Date::now().as_millis() as f64;
 
            // コアライブラリと同じロジックをサーバーサイドで実行
            let n = body.data.len();
            if n == 0 {
                return Response::error("Empty data", 400);
            }
 
            let mean = body.data.iter().sum::<f64>() / n as f64;
            let variance = body.data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / n as f64;
            let std_dev = variance.sqrt();
 
            let end = Date::now().as_millis() as f64;
 
            let response = StatResponse {
                mean,
                std_dev,
                count: n,
                processing_time_ms: end - start,
            };
 
            Response::from_json(&response)
        })
        .get("/health", |_, _| Response::ok("OK"))
        .run(req, env)
        .await
}

デプロイは Antigravity のエージェントに「Cloudflare Workers にデプロイして」と依頼するだけです。

# Antigravity のターミナルで実行(エージェントが自動補完)
cd workers
wrangler deploy
# → Uploaded cf-workers-rust (1.2 sec)
# → Deployed at: https://cf-workers-rust.masakihirokawa.workers.dev

応用パターン — WASM + Antigravity エージェント連携

パターン 1: Antigravity で WASM バイナリサイズを最適化

WASM バイナリサイズはロード時間に直結します。Antigravity のエージェントに依頼することで、最適化を自動化できます。

プロジェクトのチャットに「WASM バイナリが 500KB を超えています。最適化して」と入力すると、エージェントは以下のような対応を自動実行します。

  1. wasm-optbinaryen ツール)を使った最適化
  2. wee_alloc カスタムアロケータの導入提案
  3. 未使用の web-sys 機能フラグの削除
  4. cargo bloat を使ったバイナリ分析
# エージェントが提案・実行する最適化コマンド例
wasm-opt -Oz --strip-debug ./pkg/wasm_core_bg.wasm -o ./pkg/wasm_core_bg_opt.wasm
 
# 最適化前後の比較
ls -lh ./pkg/wasm_core_bg.wasm        # 842KB
ls -lh ./pkg/wasm_core_bg_opt.wasm    # 312KB(62% 削減)

パターン 2: Antigravity Manager Surface でマルチエージェントテスト

Antigravity の Manager Surface を活用して、WASM モジュールのテストを並列実行できます。

GEMINI.md にプロジェクトのコンテキストを記述しておくことで、エージェントが WASM テストの意図を正確に理解します。

<!-- GEMINI.md -->
# WASM Core ライブラリ
 
## このトピックの全体像
このプロジェクトは Rust + WebAssembly で実装した高速計算ライブラリです。
 
## テスト実行
- ユニットテスト: `wasm-pack test --headless --firefox`
- ベンチマーク: `cd app && npm run bench`
- 本番ビルド: `wasm-pack build --target web --release`
 
## 注意事項
- WASM のメモリは線形で成長する。メモリリークに注意
- `wasm-bindgen` の型マッピングは `src/lib.rs``#[wasm_bindgen]` を参照
- Cloudflare Workers デプロイ前に `wrangler dev` でローカル確認を行うこと

トラブルシューティング

よくあるエラーと対処法

エラー 1: error[E0277]: the size of T cannot be known at compilation time

これは Rust の動的サイズ型(DST)制約によるエラーです。Antigravity のエージェントチャットにエラーメッセージをそのままペーストすると、正確な修正案(Box<T>Rc<T> の利用、Sized バウンド追加など)を提示してくれます。

エラー 2: wasm-pack build が "no candidates" で失敗

Cargo.toml[lib] crate-type = ["cdylib"] が欠けている場合に発生します。Antigravity は Cargo.toml を解析して即座に指摘します。

エラー 3: TypeScript の型エラー — WASM 関数の返り値が any

wasm-pack が生成する .d.ts が不完全なケースです。Antigravity に「WASM バインディングの TypeScript 型を厳密にして」と依頼すると、ラッパー型定義を自動生成してくれます。

エラー 4: Cloudflare Workers デプロイ後に 500 エラー

Worker の WASM バイナリサイズ上限(1MB 圧縮後)を超えているケースがあります。wasm-opt による最適化が必要です(上記のパターン 1 参照)。


パフォーマンス考慮事項

ベンチマーク結果(参考値)

処理JavaScriptRust WASM速度比
100万件の統計計算185ms12ms15.4×
4K 画像グレースケール変換340ms28ms12.1×
FNV1a ハッシュ(1MB データ)98ms5ms19.6×

メモリ使用量の最適化

WASM のメモリは WebAssembly.Memory オブジェクトとして管理され、一度確保したメモリは自動では縮小しません。長期間稼働するアプリでは以下を意識してください。

  • 大きなデータを処理した後に WASM モジュールを再初期化
  • wee_alloc でデフォルトアロケータを軽量化
  • Worker スレッドで WASM を実行しメインスレッドへの影響を最小化

個人開発者の視点から(実体験メモ)

ここまでの要点

Rust + WebAssembly と Antigravity の組み合わせは、2026年のウェブ開発において最もパワフルな構成のひとつです。

  • パフォーマンス: JavaScript の10〜20倍の実行速度
  • 安全性: Rust のメモリ安全性でバグを設計段階で防止
  • AI 支援: Antigravity がコンパイルエラー・型変換・デプロイを自動化
  • エッジ対応: 同じ Rust コードをブラウザと Cloudflare Workers で共用

Antigravity なしでの Rust WASM 開発は、コンパイルエラーとの戦いで多くの時間を費やしがちでしました。しかし AI エージェントの力を借りることで、アーキテクチャ設計とビジネスロジックに集中できるようになります。

ぜひ本記事のサンプルコードを出発点に、あなた自身の高速 WASM アプリを Antigravity で構築してみてください。

関連記事

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

アプリ開発2026-07-04
課金済みなのに広告が消えない — StoreKit 2 の Transaction.updates を起動直後に取りこぼす競合を Antigravity と塞いだ記録
起動直後に届く StoreKit 2 のトランザクションを取りこぼす競合を、View 寿命ではなくアプリ寿命にリスナーを固定して塞いだ実装記録。currentEntitlements での照合、finish() の徹底、StoreKitTest での回帰テスト化まで。
アプリ開発2026-06-26
生成も配信も任せても、署名鍵だけは渡さない — AI 主導の配布パイプラインで鍵の管理と引き継ぎを設計する
AI Studio や Antigravity が生成から内部テスト配信までを肩代わりする時代でも、アプリの署名鍵だけは別格です。鍵を失えば、そのアプリは二度と更新できません。個人開発で複数アプリを長く運用してきた立場から、アップロード鍵とアプリ署名鍵の分離、鍵の保管、そして万一の引き継ぎまでを設計としてまとめました。
アプリ開発2026-06-26
埋め込みエミュレータでは緑なのに、実機で初めて崩れる — AI 生成 Compose アプリに実機差を塞ぐ検証ゲートを置く
AI Studio はテキストから Kotlin/Compose アプリを生成し、埋め込みエミュレータで動かし、USB で実機へ送るところまで一画面でつなぎました。けれどエミュレータで通った画面が、手元の実機で初めて崩れることがあります。個人開発で複数アプリを抱える立場から、生成物に実機差を塞ぐ検証ゲートを据える設計をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →