Show HN: Agent Draw:あなたが話す間、エージェントが描画する TLDraw を基盤としたツール

2026/07/06 23:50

Show HN: Agent Draw:あなたが話す間、エージェントが描画する TLDraw を基盤としたツール

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

最も大きな進歩は、「2draw」と呼ばれるインタラクティブな描画ゲームであり、React の tldraw SDK を基盤とし、AI エージェントに無限キャンバス上を自律的に描画する能力を付与します。Claude Opus 4.8 という高度なモデルとの統合により、このシステムは人間の介入なしに複雑な視覚的な指示(例:クリケットの場面の描写など)を成功裏に実行できます。これに対し、Claude Haiku や Google Gemini といった小規模なモデルは、単純な静的構成しか生成できず、あるいは正確な図形に関するタスクにおいては完全に失敗することがしばしば見られました。

技術的には、このプロジェクトは遅い単一ターンのリクエストを効率的なエージェントループに置き換え、冗長なビューアクションを削除することでパフォーマンスを最適化しています。また、Cloudflare Workers をホスティング用に採用し、複数の描画キャプチャがオーバーラップエラーを伴わずに順次処理されるように、特定の FIFO キュー機構を用いています。これにより、以前の遅いストリーミングインタフェースで発生していた問題を解消しています。システムでは、Mistral の Voxtral モデルを使用した音声文字起こしパイプラインを組み込み、ユーザーの発話をキャプチャするとともに、カスタムプロンプトを用いてモデルに指示を与え、適切な視覚的な形態を選択させる一方で、verbatim な文字起こしや停滞を引き起こすことを禁止しています。

開発者の観点からは、MIT ライセンス下にあるソースコードは、同様の生成アートアプリケーションを構築するための堅牢なテンプレートを提供します。ユーザーは、tldraw SDK の非商用利用向けの無料ホビーライセンスに従う条件の下で、抽象的なテキストプロンプトと精密なデジタルイラストの間のギャップを埋える高品質な視覚的創造能力を利用できるようになりました。

本文

tldraw 上に AI エージェントを統合:『Agent Draw』の開発と実装

React を対象とする無限キャンバス SDKtldraw上で、共有キャンバス形式の推測ゲーム「2draw」を開発した際のエージェント活用から着想を得た新たなツール、Agent Drawについて紹介します。このツールの主な機能は、ユーザーのプレゼンテーション中に、AI エージェントが代わりにキャンバス上に図を描画することです。

以下の内容は、化学授業でのデモ発表時のアシスタント活用事例および技術的な実装詳細に基づいています。


🚀 Agent Draw を今すぐ試してみよう(またはソースコードを入手しよう)

  • ライブデモ:
    tldraw-agent-draw-demo.james-664.workers.dev
  • GitHub リポジトリ:
    github.com/ritza-co/tldraw-agent-draw-demo

💡 機能概要:あなたがプレゼン中に描画してくれるエージェント

ユーザーがキャンバス上に四角をドラッグして指示を入力すると、すぐに図が表示されます。これは AI エージェントがユーザーの発言に合わせてリアルタイムで描画を行っているものです。

  • 待機列(キュー)による連続動作
    • 複数の矩形を連続してドラッグすると、それらは待機列に登録されます。
    • 指示された順番に描画処理が行われます。
    • このシステムはすべて、無限キャンバスツールである tldraw の上で実装されています。

🛠️ 技術基盤と能力の検証

tldraw とは何か?

  • React を対象とする無限キャンバス SDKです。
  • ユーザーのマウス操作(形状作成・移動・矢印引くなど)と同じ API で、エージェントがコードを通じてこれらの操作を駆動します。
  • tldraw は既に公式に「エージェント起動キット」を提供しており、その上に Cloudflare Worker のサポートがあります。Agent Drawはこのキットをベースに構築されています。

描画能力の検証結果

大規模言語モデル(LLM)が単純な基本要素から成る構成を適切に処理することが確認されました。

  • 高性能モデル(例:

    claude-opus-4.8

    • 意思決定図やクリケットの風景スケッチなど、複雑な描画リクエストを完璧に処理します。
    • ペンツールを使用した完全なスケッチも可能であり、高い野望(ambition)を持っています。
  • 小型モデルの傾向:安易な妥協

    • 高性能モデルと違い、野望が低下する傾向があります。
    • claude-haiku-4.5
      の例:
      • 意思決定図は作成可能ですが、クリケット描画ではペンツールを使わず、基本要素と静的なラベル付けに留まります。
  • より弱体化したモデル(例:

    google/gemini-2.5-flash-lite

    • タスクを早期に放棄する傾向が見られました。

⚙️ 開発実装の詳細

この機能は、以下のコンポーネントにより構成されています:

  1. 新しいキャンバスツール(ドラッグ操作)
  2. 音声処理パイプライン
  3. シリアライズされた描画キュー
  4. プロンプトセクション

1. ドラッグした領域をキャプチャする

tldraw のツールは状態機械(State Machine)です。

StateNode
を継承し、以下の 3 つの状態を経由します:
idle
pointing
dragging

実際の主要処理はドラッグが完了する (

pointer-up
) イベント時に実行されます。

class AreaCaptureDragging extends StateNode {
  static override id = 'dragging'
  private bounds: BoxModel | undefined = undefined

  override onPointerUp() {
    this.editor.updateInstanceState({ brush: null })
    if (!this.bounds) throw new Error('Bounds not set')
    // キャプチャされた矩形(ページ座標系)をキャプチャセッションに渡す。
    startCaptureSession(this.bounds)
    this.parent.transition('idle')
  }

  updateBounds() {
    if (!this.initialPagePoint) return
    const currentPagePoint = this.editor.inputs.getCurrentPagePoint()
    // ドラッグ中の境界計算
    const x = Math.min(this.initialPagePoint.x, currentPagePoint.x)
    const y = Math.min(this.initialPagePoint.y, currentPagePoint.y)
    const w = Math.abs(currentPagePoint.x - this.initialPagePoint.x)
    const h = Math.abs(currentPagePoint.y - this.initialPagePoint.y)

    // tldraw 自身の選択ツールと同じインスタンス状態を利用して、ライブの選択ブラシ矩形を取得。
    this.editor.updateInstanceState({ brush: { x, y, w, h } })
    this.bounds = { x, y, w, h }
  }
}
  • 技術的なポイント:
    editor.updateInstanceState({ brush })
    を利用することで、tldraw 自体の選択ツールが使用する同じ状態を再利用し、ライブな選択ブラシ矩形を無料で取得できます。
  • 座標系: 境界(bounds)はページ座標系にあるため、ユーザーによる画面移動(パン)やズームに対しても正しく保たれます

2. 話しながら聴き続ける

キャプチャ開始直後にマイクが起動します。

AreaRecorder
はブラウザの
MediaRecorder
をラップした単純な実装です。

export class AreaRecorder {
  async start(): Promise<void> {
    this.stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    const recorder = new MediaRecorder(this.stream, { mimeType: this.mimeType })
    this.chunks = []
    recorder.ondataavailable = (event) => {
      if (event.data.size > 0) this.chunks.push(event.data)
    }
    recorder.start()
    this.recorder = recorder
  }

  async stop(): Promise<Blob> {
    // ……レコーダーを停止し、マイクを解放し、記録されたクリップを解決して返す……
    return new Blob(this.chunks, { type: this.mimeType || 'audio/webm' })
  }
}

3. 音声からテキストへの変換

音声データ(Blob)は、Cloudflare Worker の

/transcribe
ルートに送信されます。

  • 実装: Mistral の Voxtral 音声認識モデルを使用。
  • セキュリティ: サーバー側キーがデフォルトですが、訪問者が独自のヘッダーで API キーを指定した場合は独自キーが優先されます。
export async function transcribe(request: IRequest, env: Environment) {
  const form = await request.formData()
  const file = form.get('file')
  
  // 訪問者が独自に追加した場合、そのキーがサーバーのキーよりも優先される。
  const mistralKey = request.headers.get('x-mistral-api-key') || env.MISTRAL_API_KEY
  
  const outForm = new FormData()
  outForm.append('file', file)
  outForm.append('model', 'voxtral-mini-transcribe-2507')
  
  const mistralResponse = await fetch('https://api.mistral.ai/v1/audio/transcriptions', {
    method: 'POST',
    headers: { Authorization: `Bearer ${mistralKey}` },
    body: outForm,
  })
  const data = (await mistralResponse.json()) as { text?: string }
  
  return new Response(JSON.stringify({ text: data.text ?? '' }), {
    headers: { 'Content-Type': 'application/json' },
  })
}

4. 同時に複数の描画を処理する(キュー処理)

これは複数回のキャプチャを可能にする重要な部分です。

  • 1 つ目の矩形が描画中にも、2 つ目以降の矩形をドラッグできます。
  • キュー順に処理され、キャンバス上で競合しません。
  • 設計: tldraw の atom 上のモジュールレベルの状態機械として実装(単一のレコーダー・FIFO キュー・単一コンシューマー)。
export function startCaptureSession(bounds: BoxModel): string {
  // 新しい描画を開始すると、まだ記録中の音声セッションを終了する。
  if (recordingId) finalizeRecording(recordingId)
  const id = nextId()
  sessions.set([...sessions.get(), { id, bounds, status: 'recording' }])
  const rec = new AreaRecorder()
  recorder = rec
  recordingId = id
  rec.start().catch(/* セッション上でマイクの許可エラーを表面化させる */)
  return id
}

処理フロー:

  1. 新しいキャプチャ開始 → 現在記録中の音声セッション終了 → キュー登録。
  2. コンシューマーがキュー内のセッションを 1 つずつ処理(トランスクリプション → 描画)。
  3. シリアライゼーション: エージェントは一度に 1 つのリクエストしか実行しないため、新しいキャプチャは関係なく順番待ちになります。
async function processQueue(): Promise<void> {
  if (processing) return // 単一のコンシューマー
  
  processing = true
  try {
    while (queue.length > 0) {
      const id = queue.shift() as string
      const session = getSession(id)
      const blob = pendingBlobs.get(id)
      
      patchSession(id, { status: 'transcribing' })
      const text = await transcribe(blob)
      
      patchSession(id, { status: 'drawing' })
      await requestDrawInArea(agentRef, text, session.bounds)
      removeSession(id)             // このキャプチャ用のオーバーレイをクリアする
    }
  } finally {
    processing = false
  }
}
  • 採用の背景: ライブストリーミング描画ではラグが発生したため、「一度にキャプチャしてその後話す」モデルに変更。また、キューによる導入で「2 つのキャプチャが互いにキャンセルする」という重なり問題を解決しました。

5. エージェントがタスク完了まで描画を続けるようにする

各セッションのトランスクリプトと境界情報を

requestDrawInArea
に渡します。

  • 重要: スターターキットのフルなエンティツループ (
    agent.prompt
    ) を使用し、単発の
    agent.request
    は使いません。
  • 理由:
    prompt
    を使用すると、モデルは自らのターンを続け、追加要素がなくなるまで自動的に進み、1 つのコールですべての描画を完了できます。
  • 対照的に、単発リクエストでは 1 つだけの形状しか描画されません。
export async function requestDrawInArea(
  agent: TldrawAgent,
  text: string,
  bounds: BoxModel
): Promise<number> {
  const area = { type: 'area' as const, bounds, source: 'user' as const }
  ensureMode(agent, 'working')
  const before = agent.editor.getCurrentPageShapeIds().size
  
  try {
    await agent.prompt({ message: buildAreaMessage(text), contextItems: [area] })
    return agent.editor.getCurrentPageShapeIds().size - before
  } finally {
    ensureMode(agent, 'idling')
  }
}
  • 過去の改修: 以前は単発リクエスト問題から手動でループを実装しましたが、
    agent.prompt
    の独自完走が確認されたため、足場コードを削除しました。

6. 動作を高速化する

固定領域での描画において、以下の 2 つのアクションを削除することで、1 キャプチャあたりのモデルコール数を約半減させました。

  • setMyView
    : カメラビュー移動。チャットパネルでは有用だが、エリアキャプチャではユーザーは「何が描かれたか」のみが見たいため不要(ラウンドトリップの原因)。
  • review
    : リンターによる形状検証と修正スケジュール。これも最終的なモデルコールの増加要因であり、固定領域描画には寄与しないため削除。
// review と setMyView を削除 — これらは描画ごとに追加のラウンドトリップを強制的に発生させ、
// 固定領域の結果改善には寄与しないため。Utils は他のモードでも引き続き登録される。
actions: [
  ThinkActionUtil.type,
  CreateActionUtil.type,
  PenActionUtil.type,
  // ……残りのアクション……
]

7. モデルに「描画」をさせ、「文字起こし」だけをさせない

システムプロンプトに以下の指示を追加しています。

  • 視覚形式の自己評価: モデルに対し、どのような視覚形式が最適かを自ら評価させます。
  • トランスクリプトの流用禁止: テキストをそのまま壁のように描画させません。
  • 具体的な指示事項:
    1. 形状名(「赤い円を描く」)や図解は、複数ボックスではなくよく描画されたものを表示。
    2. 定義や説明は、全文テキストブロックではなく、キーワード付きのラベル付き図式
    3. 図表やプロセスは、ラベル付きノードと矢印を使用。
    4. チャート:定量的または比較的内容の場合に使用。
  • 動作方針:
    • 曖昧な場合でも最善の見解を持つ。
    • 決して停止しない(少なくとも 1 つの形状を必ず出力)。
    • 単一のターンですべての結果を構築する推奨。

8. ツールをツールバーに登録

標準オーバーライド API を通じてツールを登録し、ビルトインツールの横にアイコンとショートカットが並ぶようにします。

const tools = [AreaCaptureTool, TargetShapeTool, TargetAreaTool]

const overrides: TLUiOverrides = {
  tools: (editor, tools) => ({
    ...tools,
    'area-capture': {
      id: 'area-capture',
      label: 'Agent draw',
      kbd: 'a',
      icon: agentDrawIcon,
      onSelect() { editor.setCurrentTool('area-capture') },
    },
  }),
}

<Tldraw 
  licenseKey={import.meta.env.VITE_TLDRAW_LICENSE_KEY} 
  tools={tools} 
  overrides={overrides} 
  components={components} 
/>

📜 ライセンスと利用について

  • コードライセンス: MIT ライセンス。
    • ローカル環境での利用は無料です。
    • 下敷きとなっているスターターキットも同様に公開されています。
  • tldraw SDK ライセンス: 別件専用のライセンスが必要です。
    • 公衆向けデプロイにはライセンスキーの取得が必須。
    • 非商業プロジェクトについては、tldraw から無料の愛好家ライセンスを受けることができます。

同じ日のほかのニュース

一覧に戻る →

2026/07/09 5:05

FAANGシミュレーター

## Japanese Translation: 「FAANG™ Life Simulator featuring MILTON」は、エントリーレベルのテックワーカーが直面する激しいプレッシャーを批判的に検証する風刺モバイルゲームです。このシミュレーションでは、**1 回のタップは人生の 1 四半期を表し**、**1 つのグリッドマスは 1 ヶ年を表す**ことで、プレイヤーには急速な加齢と変動するメトリクスを管理させながら、過酷な現実を目撃させる仕組みとなっています。初期状態として Milton は 22 歳(Q1)、パフォーマンススコアが 50、バーンアウトが 10 の状態で始まり、高給与(年額 19 万ドル)と金銭的自由の欠如(退職永久資金 0%)、そして資産総額 0 が同時に存在する厳しい現実を描き出します。プレイヤーがこれらの制約の中で動き回りながら、企業が 0% のトラクションを示す中で、特定のアクションによって定義された明確な複数のエンディングへと至ります:その行為とは、**「Form HR-1099-RAT」の記入**、**「Exit Interview」への参加**、そして**「GO HOME」画面の表示**です。シミュレーション終了後、プレイヤーはその結果を 𝕏(X)に投稿し、自らの架空のキャリアの終焉をデジタル記録として残すことができます。最終的に、このプロジェクトは業界全体の課題である従業員の福祉、定着率の難しさ、一流テクノロジー企業で働く際の隠れたコストなどについて鋭い評論を行い、官方的な提携はないまま、現状の高い成長を志向する専門職モデルの持続可能性に疑問を投げかける魅力的な体験へと抽象的な企業データを転換します。

2026/07/09 0:19

Chatto はオープンソースになりました

## Japanese Translation: Chatto は、セルフホスト用に設計された新たにリリースされたオープンソースのグループチャットおよびチームチャットアプリケーションです。ユーザーは、`brew install chattocorp/tap/chatto` で Homebrew を使用して Linux (x86_64/ARM64)、macOS、Windows 上ですぐに試すことができます。その後、`chatto init` と `chatto run` を実行します。その核心的な強みは、コンパクトなパフォーマンス、堅牢なプライバシー、完全なデータ保護です:すべてのデータは静態で暗号化され、アカウント削除時にユーザー固有の鍵が完全に「破棄」され、データ痕跡は残りません。連邦システムとは異なり、Chatto はサードパーティの追跡がない単一サーバーのコミュニティモデルを運用し、クライアントは同時に複数のサーバーに直接接続できます。内蔵された音声通話、ビデオ通話、画面共有はすべてエンドツーエンドで暗号化され、インフラストラクチャのキャパシティに応じてスケーリングします。現在、production 使用のためにバージョン 0.4 が安定しており、Chatto は広告やベンダーロックインを回避しています。有料の「Chatto Cloud」サービスが間もなくヨーロッパ所有のインフラ上で開始され、広告なしでロックインなく安全なホスティングを提供し、自動スケーリング、夜間のバックアップ、ダウンタイムなしのアップグレード、セルフホストされたサーバーとの完全互換性を提供します。追加のリージョンは 2027 年初頭に予定されています。バージョン 0.5 は安全性機能、コンテンツモデレーション、クライアントの改良に焦点を当て、予想される 1.0.0 リリースに向けて進みます(注:新しいバージョンがロールアウトするにつれて破壊的変更が発生する可能性があります)。コミュニティサポートは Chatto HQ の専用の #self-hosting チャンネルで利用でき、リリースおよび早期 Cloud ベータへのアクセスに関する更新のために低ボリュームのニュースレター(〜1 封/月)を購読することもできます。この安全かつ広告なしのプラットフォームは、現代のマルチメディア機能を損なうことなくユーザーの主権を優先します。 ## Text to translate: Chatto is a newly released open-source group and team chat application designed for self-hosting. Users can immediately try it on Linux (x86_64/ARM64), macOS, or Windows via Homebrew with `brew install chattocorp/tap/chatto`, then run `chatto init` and `chatto run`. Its core strengths are compact performance, robust privacy, and full data protection: all data is encrypted at rest and per-user keys are completely "shredded" upon account deletion, leaving no data trails. Unlike federated systems, Chatto operates on a single-server community model with no third-party tracking; clients can connect directly to multiple servers simultaneously. Built-in voice, video calls, and screen-sharing are fully end-to-end encrypted and scale with infrastructure capacity. Currently stable at version 0.4 for production use, Chatto avoids ads and vendor lock-in. A paid "Chatto Cloud" service is launching soon on European-owned infrastructure, offering secure hosting without ads or lock-in, automatic scaling, nightly backups, zero-downtime upgrades, and full compatibility with self-hosted servers; additional regions are expected in early 2027. Version 0.5 will focus on safety features, content moderation, and client polishing, leading to the anticipated 1.0.0 release within 6–12 months (note: breaking changes may occur as new versions roll out). Community support is available at Chatto HQ via a dedicated #self-hosting channel, and users can subscribe to a low-volume newsletter (~1 email/month) for updates on releases and early Cloud beta access. This secure, ad-free platform prioritizes user sovereignty without compromising modern multimedia capabilities.

2026/07/09 3:00

Grok 4.5

## Japanese Translation: SpaceXAI は、コーディング、エージェンタスク、複雑な知識業務に特化して Cursor と共同開発された、現時点で最も高度なモデルである Grok 4.5 を発売しました。本モデルは、単一のプロンプトからエンドツーエンドのアプリケーションを構築する(太陽系など細部の模擬を含む)などの強力な能力を示していますが、主要なベンチマークでは 3 位にランクインしています:DeepSWE 1.0 で 62.0%、Terminal Bench 2.1 で 83.3%、SWE Bench Pro では解決率が 64.7% と、GPT-5.5 xhigh および Fable に及ばない結果となっています。本モデルは、数万台の NVIDIA GB300 GPU を使用し、高度なデータ選別技術と、トークンごとの知能に焦点を当てた強化学習戦略を採用することで、同等モデルと比較して約 4.2 倍のトークン効率を達成しています。 Grok 4.5 は、入出力トークンあたりそれぞれ 100 万トークンで 2 米ドルおよび 6 米ドルという高速サービスを提供しており、限定期間中の無料利用オファーも用意されています。現在、Excel リサーチや PowerPoint の図表作成を強化する目的で Grok Build、Cursor、SpaceXAI コンソールに統合されていますが、ヨーロッパ連合では 7 月中旬のローンチまでの間利用できません。

Show HN: Agent Draw:あなたが話す間、エージェントが描画する TLDraw を基盤としたツール | そっか~ニュース