Antigravityでスライド作成ツールを作ってみた

1. はじめに

こんにちは。NewITソリューション部の井口です。

Googleのエージェントファーストな新しいIDE「Antigravity」を使い、スライド作成ツールを実際に作ってみました。まだ機能としては不十分ですが、どのようなものを作ったのか、またAntigravityの使用感についてまとめたいと思います。

2. Antigravityとは

「Antigravity」はGoogleが昨年11月にリリースしたVS CodeベースのIDEです。最大の特徴は、エディタ・ターミナル・ブラウザを横断してAIエージェントが自律的に開発を進める「エージェントファースト」な開発体験にあります。開発者はタスクを指示するだけで、エージェントが実装計画を立てて実装を行い、動作の検証まで行うことができます。

  • Implementation Plan: タスクをどのように実装するかの計画書
  • Task List: タスクの進捗管理用リスト
  • Walkthrough: 変更の説明や動作確認手順などをまとめたドキュメント
  • Screenshot: ブラウザSubagentが取得したスクリーンショット
  • Browser Recording: ブラウザSubagentが行った操作の録画
  • Knowledge: タスクを進める中で発見した重要な知見を自動的に収集・整理したもの

ScreenshotやBrowser Recordingなどとある通り、Antigravityの特徴としてBrowser Subagentという機能があります。これによってエージェントがブラウザを操作することが可能になっています。これによって、Webアプリケーションの動作を確認したり、上のようなArtifactを自動的に作成して人間のレビューの材料にしたりすることができます。

他にも、エージェントが従うべき決まりを定めるRulesや、特定の作業の進め方を指示するWorkflowsといった機能があります。一般的な機能としてはMCPやSkillsも備えています。詳しくはドキュメントを参照してください。https://antigravity.google/docs/agent

3. スライド作成ツールの実装

3.1 どのようなものを作りたいか?

私は部内の勉強会など、プレゼン用の資料を作成する際に`Marp`というスライド作成ツールを利用しています。

Marp – Markdown Presentation Ecosystem

特徴はMarkdownでスライドを記述することができるという点です。簡単なスライドであればPowerPointのようなGUIツールに頼らなくても十分な資料を作成できるため、非常に重宝しています。

一方で欠点もあり、複雑なレイアウトを作成したい場合にはHTMLやCSSを記述する必要があります。そのため、Markdownでスライドが作成できるというメリットを享受できない場面が多々あります。

---
marp: true
style: |
  .columns {
    display: flex;
    gap: 1rem;
  }
  .columns > * {
    flex: 1;
  }
---

# 2段組みの例(Flexbox)

<div class="columns">
<div>

## 左側のコンテンツ

- ポイント1
- ポイント2
- ポイント3

</div>
<div>

## 右側のコンテンツ

- データA
- データB
- データC

</div>
</div>

スライドの作成にもコーディングエージェントを活用しているので、PowerPointのようなGUIツールはなるべくであれば避けたいと考えています。

Slidevに関してはレイアウトを扱う方法が用意されており、組み込みのテンプレートの他自分でテンプレートを作成できるようです。(https://sli.dev/guide/layout
Quartoは主にアカデミックな場での利用を想定した組版システムのようです。様々な種類の出版物の出力に対応しており、その中でプレゼンテーション用のスライドにも対応しています。Markdownの拡張として以下のような記述で自由度の高いレイアウトを実現できるようです。(https://quarto.org/docs/presentations/revealjs/#multiple-columns

どちらもまだ試せてはいないので実際の使用感はわかりません。一方でMarkdownではないレイアウトの表現に特化した文法でスライドを作成できてもよいのではと考えました。そこで、コンテンツはMarkdownで簡単に記述できるようにしつつ、かつ複雑なレイアウトはスライド専用に考案した文法で記述できるようなDSL(ドメイン固有言語)の定義と、それを解釈してHTMLへ変換するパーサを実装することにしました。

今回の目標は、とりあえず動作するものを実装し、どのような体験が得られるかを確認することとしました。

3.2 DSLの設計

今回はGeminiのアプリで対話しながら議論を進めて一旦以下のようにDSLを定めました。

概要は以下の通りです。

  • CSSのグリッドレイアウトをベースにする
  • スライド1ページを以下の要素で構成する
    • Layoutブロック:グリッドの設計図。`grid-template-areas`相当の情報をアスキーアートで記述
    • Styleブロック: CSSのスタイル定義
    • コンテンツブロック: Markdownで記述。Layoutブロックで定義したエリア名と紐付ける

ざっくりとした例は以下のようになります。

===
[Layout]
|      | 1fr      | 1fr      |
| auto | ^(Title) | ^(Title) |  // 2列結合の上・中央揃え
| 1fr  | ^[Main)  | _(Image] |  // 左は上・左寄せ、右は下・右寄せ

[Style]
.Title {...CSSを記述できる...}
.Main {...}
.Image { font-size: 0.8rem; color: #777; }

---Title
# Next-Gen Slide Engine
---Main
### 特徴
- **CSS Grid直結**: 自由な2次元配置
- **Style分離**: Markdownが汚れない
- **直感的**: アスキーアートでレイアウト

---Image
![サンプル画像](assets/sample-image.png)

この時点でまだCSSの記述が必要など考慮が足りていない部分もありますが、今回はとりあえず動くものを作ることを優先し、細かい部分は今後改善していくことにしました。

これまでの議論で完成した、MarkdownのポータビリティとCSS Gridの表現力を融合させた**「次世代スライド作成記法」**の全容をまとめます。

このシステムの核心は、**「空間設計(Layout)」「装飾(Style)」「内容(Markdown)」を「名前(Class Name)」で繋ぎつつ、物理的に分離する**設計にあります。

---

## 1. 全体構造(ファイル構成)

スライド単位の区切りは `===`、スライド内の要素単位の区切りは `---ClassName` を使用します。

```text
===
[Layout]
(設計図:グリッドのサイズと配置)

[Style]
(装飾:CSSクラスの定義)

---ClassName
(Markdownコンテンツ)

\`\`\`

---

## 2. [Layout] ブロック:位置指定型定義

左上  を原点とし、行列の「位置」によって役割を固定します。パーサーは内容を推測せず、場所で意味を確定させます。

| セル位置 | 役割 | 内容の例 |
| --- | --- | --- |
| **左上 (0,0)** | **空白** | 原点として読み飛ばす。 |
| **1行目 (0, 1〜n)** | **列幅 (Columns)** | `1fr`, `200px`, `auto` |
| **1列目 (1〜m, 0)** | **行高 (Rows)** | `100px`, `1fr`, `auto` |
| **内部 (1,1〜)** | **エリア定義** | `^(Title)`, `^[Body)`, `_(Note]` |

### 配置(アライメント)記号の文法

垂直方向は「接頭辞」、水平方向は「囲み記号」で直感的に指定します。

* **垂直方向(先頭1文字)**:
* `^` : 上寄せ (`start`)
* `_` : 下寄せ (`end`)
* (なし) : 中央 (`center`) または ストレッチ (`stretch`)


* **水平方向(囲み)**:
* `[Name)` : 左寄せ (`start`)
* `(Name]` : 右寄せ (`end`)
* `(Name)` : 中央揃え (`center`)
* `[Name]` : ストレッチ (`stretch`)

---

## 3. [Style] ブロック:純粋CSS

独自のDSL(独自言語)を構築せず、CSSの資産をそのまま活用します。

* **書式**: `.ClassName { property: value; }`
* **思想**: 実装をシンプルに保ち、ユーザーがCSSの知識をそのまま発揮できるようにします。タイポや不一致はブラウザの挙動に準じる「自己責任(GIGO)」の原則を採用します。

---

## 4. コンテンツ・セパレータ:`---Name`

Markdownブロックを、Layout図で定義したクラス名(エリア)へ明示的に紐付けます。

* **記法**: `---` の直後にクラス名を記述。
* **CommonMark互換性**: `---` の後に文字が続く場合、標準Markdownの見出しや水平線とは解釈されないため、既存の仕様を壊さずに拡張できます。
* **柔軟性**: 執筆順序は自由です。Layout図の並びと、本文の `---Name` の出現順が異なっても正しくマッピングされます。

---

## 5. 完成した記法の具体例

```markdown
===
[Layout]
|      | 1fr      | 1fr      |
| 80px | ^(Title) | ^(Title) |  // 2列結合の上・中央揃え
| 1fr  | ^[Main)  | _(Side]  |  // 左は上・左寄せ、右は下・右寄せ

[Style]
.Title { 
    font-size: 2.5rem; 
    background: linear-gradient(to right, #333, #666);
    color: white;
}
.Side { font-size: 0.8rem; color: #777; }

---Title
# Next-Gen Slide Engine
---Main
### 特徴
- **CSS Grid直結**: 自由な2次元配置
- **Style分離**: Markdownが汚れない
- **直感的**: アスキーアートでレイアウト
---Side
※ 2026年プロトタイプ仕様
```

このDSLを、次の章でAntigravityを使って実装していきます。

3.3 Antigravityでの実装

順番が前後してしまいますが、作成したコードはhttps://github.com/Furafrafrfr/slide-makerに公開しています。実際に見ながら読み進めたい方は参考にしていただければと思います。

Antigravityではユーザとの会話をタスクとして管理しており、その過程でArtifactを作成しながら、ときにはユーザにレビューを求めて実装を進めていきます。

プロンプトやSkillsの設定は行わず、デフォルトの状態で実装を進めました。

今回はベースとなるものを一つのタスクで一気に作成したうえで、細かい修正タスクを任せていく形で実装しました。メインとなるタスクと、その後に行ったWebエディタの実装タスクについて紹介します。

3.3.1 メインタスク

まず、前に紹介したDSLのまとめと合わせて実装方針や出力されるHTMLに関する要件をまとめたドキュメントを作り、それらを読ませて実装するよう指示しました。これをもとにAntigravityからImplementation Planが出力されます。Implementation Planでは主に以下の要素が含まれていました。

  • タスクのゴール
  • 予想される変更
  • 成果物の検証計画

事前にドキュメントを用意するとそれをもとにImplementation Planが作成されます。ただし、最初のImplementation Planはかなり抜け漏れが多い印象でした。最終的に何を作るかという部分の概要はしっかりと理解してくれますが、実装するうえでのコードの設計や出力されるHTMLの形式などは最初の段階ではほとんど抜け落ちていました。

基本的にImplementation Planの中にあるものを実装するようです。今回のように別ファイルでタスクを記述しておいても、実装中にそのファイルを見てくれるというようなことはありませんでした。しっかりとImplementation Planの中に必要な情報を盛り込む必要があります。

私はAntigravityの操作はコードを見る必要がない場合やMarkdownのプレビューが機能していない場合を除いてAgent Managerという画面でレビューを行っていました。この画面は今開いているディレクトリ以外にも、過去に開いたことのあるプロジェクトで実行したタスクを横断的に管理できる画面になります。複数のプロジェクトで並行して作業するための機能かと思いますが、画面が大きくて見やすいので利用していました。

Implementation Planに問題がないことが確認出来たら、そのまま実装を依頼します。完了するとWalkthroughが作成されます。Walkthroughでは以下のような内容がまとめられていました。

  • 実装した機能
  • プロジェクトの構成
  • 動作確認手順

いくつかタスクを渡した限りだと、Implementation Planの実装の部分については概ね網羅してくれますが、検証計画については他の部分と比べるとやり忘れが見られることが多い印象でした。RulesやWorkflowの設定によって、このあたりを強化できる可能性はあるかと思います。

基本的には`タスクを投げる→Implementation Planをレビュー→実装が完了したらWalkthroughと動作確認`の流れを繰り返しています。

3.3.2 Webエディタの実装

最初に作成していたのはCLIツールでしたが、次のステップとして同じコアロジックを使ったWebエディタの実装もAntigravityに任せてみました。具体的には、コアロジックをライブラリとして切り出したうえで、Next.jsを利用して簡単なエディタとプレビュー画面を作成するタスクを与えました。

このタスクでも、Implementation Plan → 実装 → Walkthrough という流れは変わらず、UIを伴うWebアプリケーションでも同じワークフローで実装を進められることを確認できました。エディタ側ではテキストエリアにDSLを入力し、右側のプレビューでAntigravityが実装したパーサ/コンパイラを通じて生成されたHTMLを確認できるようになっています。

上の画像は私が実際にWebエディタを操作している様子を録画したものです。Browser Subagentを利用して録画しようとしたもののうまく行きませんでした。詳細は後述します。

CLIツールだけの場合と比べてレイアウトの試行錯誤がしやすくなり、DSLの確認にも役立ちました。

3.4 完成したものについて

3.4.1 成果物

上で出したタスク以外にも以下のようなタスクを与えました。

  • 印刷の際のレイアウトの調整
  • npm workspaceでのモノレポ管理への変更
  • Webエディタの実装

最終的にはモノレポの中で以下のパッケージを管理する形になっています。

  • core: スライド作成エンジン本体
  • cli: CLIツール
  • web: Webアプリケーション

3.4.2 内部の実装について

コードの制約は特に設けてはいませんでしたが、参考までにどのように実装しているかもざっくりと見てみます。

coreパッケージはクラスを多用して実装されていました。大きく分けてDSLの中間表現を生成するParserクラスと、HTMLを生成するHtmlCompilerクラスに分かれていました。

Markdownパーサを抽象化して外から差し替えられるようにと指示したのがAdapterパターンとして解釈され、オブジェクト指向のように実装されたのかもしれません。

 

export class MarkdownItAdapter implements MarkdownParser {
  private md: MarkdownIt;

  constructor() {
    this.md = new MarkdownIt({
      html: true,
      linkify: true,
      typographer: true
    });
  }

  render(markdown: string): string {
    return this.md.render(markdown);
  }
}

ロジックとしては、Parserクラスがテキストを一行ずつ走査しながらSlideというインターフェースを持つオブジェクトに変換し、それをCompilerクラスがHTMLのひな型に当てはめてHTMLの文字列を返すという流れになっており、かなり素朴なやり方に見えます。

cliパッケージはかなり短く、commander.jsを使ったCLIの定義とcoreパッケージの呼び出しが中心になっていました。

webパッケージはNext.jsで実装することと簡単な画面構成だけ指示しましたが、その通りになっていました。

コンポーネントなど他にもありますが以下のような1画面で構成されています。

export default function Home() {
  const [source, setSource] = useState(INITIAL_SOURCE);
  const [html, setHtml] = useState("");

  // Memoize compiler instances
  const { parser, compiler } = useMemo(() => {
    return {
      parser: new Parser(),
      compiler: new HtmlCompiler(new MarkdownItAdapter()),
    };
  }, []);

  useEffect(() => {
    try {
      const slides = parser.parse(source);
      const generatedHtml = compiler.compile(slides);
      setHtml(generatedHtml);
    } catch (e) {
      console.error("Compilation error:", e);
      // Optional: Display error in UI or just keep previous valid HTML
    }
  }, [source, parser, compiler]);

  return (
    <main className="flex min-h-screen w-full h-screen overflow-hidden flex-col md:flex-row">
      <div className="w-full h-1/2 md:w-1/2 md:h-full overflow-hidden print:hidden">
        <Editor value={source} onChange={setSource} />
      </div>
      <div className="w-full h-1/2 md:w-1/2 md:h-full overflow-hidden print:w-full print:h-full print:absolute print:top-0 print:left-0 z-10">
        <Viewer html={html} />
      </div>
    </main>
  );
}

この実装は改善の余地があると感じていて、特にuseEffectの中で状態の更新が行われているのが気になりました。Reactの考え方に則るならばレンダーのたびにHTMLを再計算するのが基本で、useMemoでメモ化するのがよいと思います。

全体として、とりあえず動くものを作るということに関しては達成できているとは思うものの、それ以上ではないと感じました。実際のプロダクトでは何かしらの目的のために、機能以外にも拡張性や保守性を考慮したい、テストコードも充実させたいといった要望があると思います。今回の実装はそのような点ではまだまだ改善の余地があると感じました。

3.4.3 完成したものを触っての考察

実際にできたものを少し触ってみて以下のようなことを考えました。

  • ユーザがCSSを書かなくてよくなれば表現の幅は深めつつMarkdownで手軽にスライドを作成できるツールになると感じた
  • 現状では出力されるHTMLやCSSについて想像できないとうまく使えないかもしれないと感じた
  • 上のような内部の実装をうまく隠蔽できればより理解しやすいツールになるかもしれない
  • 内部でMarkdownを利用するDSLとして作ったが、Markdownの部分を別のフォーマットに置き換えられるような仕組みにしても面白いかもしれない

まだまだツールとしては完成とは言えないですが、個人的には使いやすくなるのではと思っています。

DSLの文法をもう少し改善していく必要があり、その上でテキストエディタ上での補完やプレビュー、シンタックスハイライトを実装できたら便利になるかもしれないと考えています。

今回の目標であったどのような体験が得られるかを確認する、ということは達成できたと思います。

4. Antigravityを使ってみて

4.1 感想

今回はAntigravityの機能全てを網羅できたわけではないですが、核となるArtifactについてはある程度体験することができたと思っています。

既存のコーディングエージェントと比較してやはり一番特徴的なのはこのArtifactの存在です。既存のコーディングエージェントにも似たような機能はあり、例えば各エージェントに備わっているPlanモードはImplementation Planに近い部分があります。工夫次第ではこれ以外にもAntigravityが実現しようとしていることを他のコーディングエージェントでもユーザの独自のやり方で実現できるだろうと思います。

しかし、Antigravityでは、このように『最終的な成果物では必要ないが過程を評価するために必要なもの』を、Artifactというより抽象的な概念として整理しています。それがデフォルトで利用可能になっているという点が優れている部分かと考えています。

何も個別の設定をしていない状態でもArtifactがあることで、ユーザからすると最終的に何を作るのかということを筋道を立てて考えることができ、求めているものを実装しやすくなっています。しかし、依然として適切なコンテキストの管理は必要で、目的のためにコードがどのような状態になっているべきかはユーザがしっかりと定義し、それを維持する方策を考える必要がありそうです。

4.2 困ったこと

前に触れたように、アプリの動作確認としてBrowser Subagentを利用しようとしましたが、アプリの実行中にエラーが発生してうまく動作しませんでした。エラーの原因はまだ把握できていませんが、このエラーで何度も止まっているのにもかかわらず同じやり方で繰り返し操作されてしまうという問題がありました。

また、Browser Subagentは今回利用していたWSL2環境からはそのままでは正常に連携できませんでした。WSL2 (NAT) 環境で Antigravity のブラウザ連携を正常に動作させる方法を参考にすることで一応動かすことはできましたが、WSL2への対応も今後改善されてほしいと感じました。

5. まとめ

ここまでの体験を踏まえた全体的な感想としては、コードではなくArtifactを中心にレビューしていくスタイルが印象的でした。少なくとも、そこまでの仕組みを他のコーディングエージェントでまだ構築できていない私にとっては新鮮でした。AGENT.mdやSkillsのような設定、Gemini以外のモデルでの動作についてはまだ試せていないので、今後試してみたいと思います。

Googleの新しいエージェントファーストIDE「Antigravity」を使ってスライド作成ツールを実装してみました。無料でも利用できますので、興味がある方はぜひ試してみてください。

6. 最後に

もし弊社にご興味がありましたら、お問い合わせからご連絡ください。

いいね (←参考になった場合はハートマークを押して評価お願いします)
読み込み中...

注意事項・免責事項

※技術情報につきましては投稿日時点の情報となります。投稿日以降に仕様等が変更されていることがありますのでご了承ください。

※公式な技術情報の紹介の他、当社による検証結果および経験に基づく独自の見解が含まれている場合がございます。

※これらの技術情報によって被ったいかなる損害についても、当社は一切責任を負わないものといたします。十分な確認・検証の上、ご活用お願いたします。

※当サイトはマイクロソフト社によるサポートページではございません。パーソルクロステクノロジー株式会社が運営しているサイトのため、マイクロソフト社によるサポートを希望される方は適切な問い合わせ先にご確認ください。
 【重要】マイクロソフト社のサポートをお求めの方は、問い合わせ窓口をご確認ください