AI駆動のUI生成ツールv0を試してみた

AI駆動のUI生成ツールv0を試してみた

概要

今回は、Vercelが新しく提供しているAI駆動のUIジェネレーター「v0」について紹介します。

v0は、自然言語の簡単なテキストプロンプトからWebページのUIデザインや実装までを自動で生成してくれます。

ReactやNext.js、Tailwind CSSといった最新の技術スタックを使用しており、クオリティーの高いUIを瞬時に実装できるのが特徴です。

v0のプラン

v0はFreeプランでも利用できます。

Freeプランでは、チャットの回数が10回程度/0.5~1dayと制限が設けられております。

Freeプラン以外にも、PremiumやEnterPriseといったプランがあります。

  • Free ($0)

    →対象者:探索を楽しみたい個人向け

    • v0.dev/chatへのアクセス
    • 月間200クレジット
  • Premium ($20(約2900円:2024/9/3現在)/月)

    →対象者: さらに多くのメッセージや生成を求めるユーザー向け

    • v0.dev/chatでの利用制限が増加
    • 月間5000クレジット
    • クレジットの追加購入オプション
    • 画像生成
    • カスタムテーマ
    • プライベート生成
  • Premium ($20(約2900円:2024/9/3現在)/月)

    →対象者: さらに多くのメッセージや生成を求めるユーザー向け

    • v0.dev/chatでの利用制限が増加
    • 月間5000クレジット
    • クレジットの追加購入オプション
    • 画像生成
    • カスタムテーマ
    • プライベート生成
    • SAML SSO
    • カスタマイズされたオンボーディング
    • 専任のCSM(カスタマーサクセスマネージャー)
    • 優先サポート
    • Slack Connect チャンネル
    • カスタムデータ保持
    • カスタムデータソース
    • ユーザーインサイトとレポート作成

何ができるのか

v0を使えば、以下のことができます!

  1. UI生成:自然言語で指示を出すだけで、美しいUIが生成されます。例えば、「SaaS価格計算機を作って」と言うだけで、洗練されたデザインの計算機が作成されます。
  2. 細かいカスタマイズ: 生成されたUIの一部を指定して、さらに細かく調整することもできます。
  3. デバッグ:コードの問題点を見つけて修正してくれます。
  4. React DOMとshadcn/uiコンポーネントの生成: v0は基本的なHTML要素だけでなく、shadcn/uiのコンポーネントも生成可能です。
  5. 履歴機能v0.dev/historyで過去の生成履歴を確認できます。

ユースケースとしては、プロトタイプの迅速な作成、デザインアイデアの探索、プログラミング学習のサポートなど、幅広い場面で活用できそうです。

v0を試してみた

今回はv0を以下の手順で試してみます。

  • v0にログイン
  • デフォルトのプロンプトを試してみた
  • カスタマイズしたプロンプトで試してみた
  • プロダクトを公開

v0にログイン

v0を利用するにあたって、Vercelのアカウントが必要になります。

自分はGitHubで既にVercelアカウントを作成していたので早速ログイン。

Vercelにログイン

ログインが完了すると、以下の画面になりますので、画面右上のアカウントをタップします。

ログイン後の画面

すると、以下のサイドメニューが表示されるので、v0.dev/chat を選択します。

v0.devを選択

これでv0を利用することが可能になりました!

v0のホーム画面

それでは早速、v0を試していきたいと思います。

デフォルトのプロンプトを試してみた

v0には、デフォルトのプロンプトがいくつか用意されております。

その中で、今回はGenerate a sticky headerを試します。

Generate a sticky headerをタップすると、以下のプロンプトが入力、実行されました。

Generate a sticky header that shrinks and becomes transparent when you scroll down. Fill the page with content so I can test.

日本語訳
スクロールダウンすると縮小して透明になるスティッキーなヘッダーを生成する。ページをコンテンツで埋めて、テストできるようにする。

実行の結果が以下です。

固定されたヘッダーの実装が20秒ほどで実装されました!

しかし、動画を見て分かるように、ヘッダーをタップした際のページ遷移の実装がされていないので、ページ遷移の実装を追加します。

以下のプロンプトを実行しました。

ヘッダーをタップした際の遷移先のページも作成してください。 日本語で回答してください。

その実行結果が以下です。

Headerコンポーネントやapp/contact/page.tsx、app/page.tsxなどが実装されました。

お問い合わせページやトップページは個別のプレビューで確認。

しかし、遷移先のページを作成した際に、Failed to load the ./components/Header library. というエラーが出ており、画面下の赤色のダイアログにFix with v0 というボタンがあったので、クリックしてみました(動画の5秒あたり)。

その様子が以下です。

AI自体が提案した実装で発生しているエラーを感知して、修正を提案するのは実装者にとってはありがたいことですね(動画では修正しきれていないですが…)。

プレビュー機能がある一番のメリットは、動作するかどうかを事前に確認できることにあると思います。

カスタマイズしたプロンプトで試してみた

今回は、以前に紹介したGPT Enginnerとの使い心地などを比較したいと思いました。

そのため、入力するプロンプトはこちらで紹介したGPT Enginner記事と同じプロンプトを入力していきます。

以下のプロンプトを入力しました。

あなたは優秀なエンジニアです。日本語で回答してください

忘れ物防止アラート「持ち物チェックメイト」というアプリを作成したいです。

家を出る前に、その日の予定や天気、持ち物リストに基づいて必要な持ち物を通知してくれるアプリです。 忘れ物をして遅刻したり、外出先で困ったりするのを防ぎます。

特定の持ち物を登録できるようにしたり、天気情報と連携して傘の必要性を通知したりする機能を追加できるようにして実装してください

その結果が出力される様子が以下です。

App.tsxやWeatherInfo.tsx、ItemList.tsxのように複数のコンポーネントを作成して出力されました!

しかし、それぞれのコンポーネントを組み合わせた実装は出力されませんでした。

この辺りの実装は、GPT Enginnerだと複数のコンポーネントを組み合わせて出力されていたので、複雑な実装はv0よりもGPT Enginnerの方が得意なのかもしれないですね。

持ち物リストには、アイテム追加のための入力ができず、アイテムの追加と削除機能が機能していなかったので、以下のプロンプトを実行しました。

アイテムの追加と追加したアイテムを削除できるようにしてください

その結果が以下です。

無事、アイテムの追加と削除機能が動くようになりました!

続いて、以前のGPT Enginnerの記事でも行なった持ち物のチェック機能を実装したいと思います。

入力したプロンプトは以下です。

アイテムの部分にチェックボックスをつけてください。

チェック開始ボタンを押した時の挙動を設定したいです。 ボタンを押した時、持ち物リストの中でチェックが全てついていたら「いってらっしゃい」という通知を、チェックがついていない項目があれば、「アイテム名+を忘れています!」という通知を表示してください

以下が実行結果です。

指示した機能がちゃんと実装されていました!

実装されたコードはこちらになります。

import React, { useState } from 'react'
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Checkbox } from "@/components/ui/checkbox"
import { Trash2Icon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { AlertCircle, CheckCircle2 } from "lucide-react"

interface Item {
  id: number;
  name: string;
  checked: boolean;
}

export default function ItemList() {
  const [items, setItems] = useState<Item[]>([])
  const [newItem, setNewItem] = useState('')
  const [notification, setNotification] = useState<string | null>(null)

  const addItem = () => {
    if (newItem.trim() !== '') {
      setItems([...items, { id: Date.now(), name: newItem.trim(), checked: false }])
      setNewItem('')
    }
  }

  const removeItem = (id: number) => {
    setItems(items.filter(item => item.id !== id))
  }

  const toggleItem = (id: number) => {
    setItems(items.map(item => 
      item.id === id ? { ...item, checked: !item.checked } : item
    ))
  }

  const startCheck = () => {
    const uncheckedItems = items.filter(item => !item.checked)
    if (uncheckedItems.length === 0) {
      setNotification("いってらっしゃい!")
    } else {
      setNotification(`${uncheckedItems.map(item => item.name).join(', ')}を忘れています!`)
    }
  }

  return (
    <div className="w-full max-w-md mx-auto">
      <h2 className="text-2xl font-bold mb-4">持ち物リスト</h2>
      <div className="flex space-x-2 mb-4">
        <Input
          type="text"
          value={newItem}
          onChange={(e) => setNewItem(e.target.value)}
          placeholder="新しいアイテムを入力"
          className="flex-grow"
        />
        <Button onClick={addItem}>追加</Button>
      </div>
      <ul className="space-y-2 mb-4">
        {items.map((item) => (
          <li key={item.id} className="flex items-center justify-between bg-white p-2 rounded shadow">
            <div className="flex items-center space-x-2">
              <Checkbox
                checked={item.checked}
                onCheckedChange={() => toggleItem(item.id)}
                id={`item-${item.id}`}
              />
              <label htmlFor={`item-${item.id}`}>{item.name}</label>
            </div>
            <Button
              variant="destructive"
              size="icon"
              onClick={() => removeItem(item.id)}
            >
              <Trash2Icon className="h-4 w-4" />
              <span className="sr-only">削除</span>
            </Button>
          </li>
        ))}
      </ul>
      <Button onClick={startCheck} className="w-full mb-4">チェック開始</Button>
      {notification && (
        <Alert variant={notification === "いってらっしゃい!" ? "default" : "destructive"}>
          <AlertCircle className="h-4 w-4" />
          <AlertTitle>通知</AlertTitle>
          <AlertDescription>{notification}</AlertDescription>
        </Alert>
      )}
    </div>
  )
}

プロダクトを公開

続いて、作成したプロダクトを公開します。

公開手順はこちらです。

GPT Enginnerのデプロイと同様にボタンをクリックのみで公開することができました!

めちゃくちゃ簡単ですね!

公開したプロダクトは以下です。

評論

v0について実際に使ってみて感じたことは、

v0を利用するメリット

  1. 迅速なプロトタイピング: UIデザインとコーディングの時間を大幅に削減できます。アイデアを素早くビジュアル化することが可能です。
  2. 一貫性のあるデザイン: shadcn/uiとTailwind CSSをベースにしているため、モダンで一貫性のあるデザインが簡単に実現できます。
  3. 学習ツールとしての活用: 生成されたコードを見ることで、React開発やTailwind CSSの使い方を学べます。
  4. 柔軟なカスタマイズ: 生成されたコードを自由に編集できるので、細かい調整可能。
  5. 商用利用可能: 生成されたコードは商用利用も可能です。

v0を利用するデメリット

  1. 利用制限: フリープランでは1日のメッセージ回数に制限があり、継続的な利用には少し物足りないかもしれません。
  2. ファイル間の依存がある実装が苦手?: ページ遷移のなど、複数ページにまたがるような複雑なプロダクトの生成には向いていないかもしれません。
  3. 特定のフレームワークに依存: 現時点ではReactとTailwind CSSに特化しているため、他のフレームワークを使いたい場合は別の選択肢を検討する必要があるかもしれません。
  4. データ利用の懸念: 生成されたコードが将来のAIモデル改善に使用される可能性があります。セキュリティが厳しいプロジェクトでは注意が必要です。

まとめ

いかがでしたか?

v0は、AIの力を借りてUIデザインとコーディングを効率化するツールであり、GPT Enginnerとはまた違った用途になるかなと感じました。

個人的には、v0はファイル構成がシンプルでUIにこだわる時に使用し、GPT Enginnerはページ遷移などのファイル構成が少し複雑になる実装に使用するイメージかなと思います。

また、v0のFreeプランの制限や、生成データの扱いについても注意が必要です。

興味のある方はぜひ、一度試してみてはいかがでしょうか?

Anycloudではプロダクト開発の支援を行っています

プロダクト開発をお考えの方はぜひAnycloudにご相談ください。

まずは相談する

記事を書いた人

しんじょう

エンジニア

しんじょう

株式会社Anycloudでエンジニアをしています