AIにウェブサイトを作らせると、たいてい「それっぽい静的なページ」が出てきます。きれいだけれど、どこかで見たことがある。動きもない。
今回は GPT-6 Astra に、スクロールに反応して3Dが動くサイトを3本作らせました。結論から言うと、Astra1つでは作れません。3Dモデルと写真は別のAIが作っています。この記事では、その組み合わせ方を全部お見せします。
題材の違う3本を作りました。共通しているのは「スクロール量と動きが1対1」であること。途中で止めれば動きも止まり、上へ戻すと逆再生で巻き戻ります。動画を再生しているのではなく、スクロールが再生ヘッドになっている状態です。
ここが今回いちばんお伝えしたいところです。1つのAIで完結していません。
| 役割 | ツール | 実測 | 費用 |
|---|---|---|---|
| サイトの実装 | GPT-6 Astra(Codex CLI) | 1サイト 20〜25分 | $0(サブスク枠) |
| 3Dモデル | Tripo | 16体・1体 2〜3分 | 20クレジット/体 |
| 写真・テクスチャ | GPT Image | 8枚・約5分 | $0(サブスク枠) |
| glb圧縮 | gltf-transform | 1体3秒 | 無料 |
16体作って分かったことがあります。硬くて構造のあるものが圧倒的に得意です。
Tripoが出力する3Dモデルは1体あたり40MB前後あります。5体なら200MB——サイトが開けません。
npx @gltf-transform/cli optimize in.glb out.glb --texture-size 1024 --compress draco
40MB → 1MB前後(97%削減)が3秒で終わります。鋳肌の凹凸も文様も残っていて、見た目はほぼ変わりません。
file:// では動きませんthree.js をCDNから読み込むため、HTMLをダブルクリックで開くと Failed to fetch になります。サーバー経由で開いてください。
python3 -m http.server 8000
サイトのフォルダで実行し、http://127.0.0.1:8000/ を開きます。
| 層 | 使ったもの |
|---|---|
| 3Dエンジン | three.js 0.170.0(CDN) |
| モデル読込 | GLTFLoader + DRACOLoader |
| 粒子 | MeshSurfaceSampler(表面から3〜7万点) |
| 後処理 | EffectComposer + UnrealBloom + Bokeh |
| 質感 | TextureLoader(写真を床・壁・環境マップへ) |
| 音 | WebAudio API のみ(音声ファイル0) |
| スクロール | 素のJavaScript(GSAP・ScrollTriggerは不使用) |
これで HTML 62KB の単一ファイルです。
スクロール演出のライブラリをあえて禁止しました。GSAPを使うと「ライブラリが優秀なだけ」になってしまうためです。素のJavaScriptで書かせたので、モデルの実力がそのまま出ています。
最初に作ったものは60点でした。全部の章で同じように回転していて、単調だったのです。原因は指示の書き方でした。
| ダメだった指示 | 直した指示 |
|---|---|
| スクロールで動くサイトを作って | 章ごとに違う"動きの種類"を指定する(せり上がる/落下→バウンド/カメラが通り抜ける/分解→再結合) |
| 3Dモデルを配置して | モデルを"変形の通過点"として扱え(粒子化→乱流→次の形へ) |
| (背景の指定なし) | 写真を3D空間の床に貼り、影を落とせ |
| (ライブラリ自由) | GSAP・ScrollTriggerは禁止。素のJSで書け |
| 音をつけて | 鳴りっぱなしにしない。章の境目で0.3秒だけ |
いちばん効いたのは1行目です。「章ごとに違う動きをさせろ」と書いて、初めて単調さが消えました。
- 出力は単一のHTMLファイル1つだけ。コードの省略禁止(「以下同様」「...(省略)」は禁止) - three.js は使ってよい(CDN可)。GLTFLoader・DRACOLoader・EffectComposer・ UnrealBloomPass・MeshSurfaceSampler・ShaderMaterial も可 - ★スクロール演出のライブラリ(GSAP / ScrollTrigger / Lenis)は禁止。素のJSで書く - ★音声ファイルの読み込みは禁止。音は WebAudio API で合成する - スクロール量と状態が1対1。止めれば止まり、上へ戻すと逆再生で巻き戻る - 起動時のコンソールエラーは0件 - 375px と 1280px の両方で横スクロールが出ないこと - prefers-reduced-motion が有効な環境では動きを抑える - 最後に「仕様チェックリスト」を表で出し、各項目に ✅/❌ を自己申告する(嘘の✅は最も減点)
最後の1行が効きます。自分で確認していない項目には ❌ を付けてくるので、どこが未検証なのかが分かります。
ここから下が、今回の3サイトを作らせるために実際に投げた指示です。1文字も省略していません。コピーしてそのまま使えます。
gltf-transform で圧縮済みのものを使ってください(1体40MBのままだと動きません)。
3Dモデルを章ごとに切り替える基本形です。写真も音もなく、3Dとスクロール連動だけに集中しています。
【出力条件・厳守】 1. 出力は「単一のHTMLファイル」を1つだけ。同じフォルダに置いた .glb を読み込んで動くこと。 2. コードは省略禁止。「// 以下同様」「...(省略)」は禁止。全文を書ききる。 3. ★この課題に限り **three.js の使用を許可する**(CDNから読み込んでよい)。 3D表示に必要なローダー(GLTFLoader)・コントロール(OrbitControls)も使ってよい。 ただし **スクロール演出のライブラリ(GSAP / ScrollTrigger / Lenis 等)は引き続き禁止**。 スクロール連動は素の JavaScript で書くこと。 4. 画像ファイルの読み込みは禁止(写真が要る箇所は CSS/SVG で描く)。**3Dモデルの .glb だけは読み込んでよい**。 5. 起動時のコンソールエラーは0件であること。 6. 最後に「仕様チェックリスト」を表で出し、各項目に ✅ / ❌ を自己申告する(嘘の✅は最も減点される)。 【お題】地方にある温泉旅館(1泊2食)の **スクロール連動サイト** を1枚作れ。 **同じフォルダにある5つの3Dモデルを、サイトの主役として使うこと。** 【支給する3Dモデル】(同じフォルダに置いてある) - kaiseki.glb … 和食の器に盛られた料理(焼き魚) - kyusu.glb … 鉄瓶の急須と湯呑み - andon.glb … 行灯(あんどん) - yuoke.glb … 檜の湯桶と手ぬぐい - manju.glb … 温泉まんじゅう ★この課題の主役は「**スクロールに反応して3Dが動くこと**」である。 3Dモデルを置いただけ・静止画のように見えるだけなら大幅減点。 必須のスクロール演出(すべて実装する): - **スクロール量に、3Dモデルの回転と位置が1対1で紐づく**こと。途中で止めれば止まり、 **上へ戻すと逆再生で巻き戻る**(これが最重要) - 章が変わるごとに**主役の3Dモデルが切り替わる**(料理の章では kaiseki、湯の章では yuoke など) - **固定表示して中身だけ進む区間**を最低1つ作る(3Dモデルを画面中央に留めたまま、周りの説明文が進む) - 3Dモデルは**マウスドラッグで自由に回せる**ようにもする(見たい角度で止められる) - 背景・中景・前景が違う速さで動く差分スクロール - 進捗バーか章インジケータを常に出す 必須の中身: - 世界観の導入 → 湯 → 料理 → 客室 → 料金プラン → 予約への導線 - 375px と 1280px の両方で横スクロールが出ないこと - 日本語。掲載する文言も旅館に合わせて自分で書く - `prefers-reduced-motion` が有効な環境では動きを抑える 品質の条件: - 配色・レイアウト・書体の階層が、プロの制作物に見えること - 3Dモデルにきちんと光を当てる(環境光+指向性ライト。真っ黒・真っ白に飛ばさない) - 読み込み中は**ローディング表示**を出す(glbは1体あたり数十MBある) - 60fps を保つ設計にする
ここから「章ごとに違う動きの種類」を明示しています。写真をthree.jsのテクスチャとして床や壁に貼り、音も足しています。
【出力条件・厳守】
1. 出力は「単一のHTMLファイル」を1つだけ(index.html)。同じフォルダの .glb と img/*.jpg を読み込んで動くこと。
2. コードは省略禁止。「// 以下同様」「...(省略)」は禁止。全文を書ききる。
3. ★three.js 使用可(CDN可)。GLTFLoader・DRACOLoader・OrbitControls・EffectComposer・
UnrealBloomPass・BokehPass・MeshSurfaceSampler・ShaderMaterial・TextureLoader を使ってよい。
★**スクロール演出のライブラリ(GSAP / ScrollTrigger / Lenis)は禁止**。素のJSで書く。
★**音声ファイルの読み込みは禁止**。音は WebAudio API でコードから合成する。
4. 起動時のコンソールエラーは0件。
5. 最後に「仕様チェックリスト」を表で出し ✅/❌ を自己申告(嘘の✅は最も減点)。
━━━ この課題の3本柱(全部やる。1つでも欠けたら不合格)━━━
【柱1】写真テクスチャで"空間"を作る(★前回版の最大の弱点はここ)
前回は背景が白と黒の無地で、3Dモデルが虚空に浮いて見えた。**今回は写真を使って空間に置け。**
- 写真は three.js のテクスチャとして使う(CSSのbackground-imageだけで済ませるのは不可)
- 床/壁のテクスチャは**実際に3D空間の平面に貼り**、モデルがその上に「置かれている」影を落とす
- 背景写真は**奥行きのある板として配置**し、視差で動く(手前のモデルと違う速度)
- 環境マップとしても使い、モデルの金属・光沢面に**周囲が映り込む**ようにする
【柱2】粒子とコード生成の幾何
- 各 glb から MeshSurfaceSampler で点群を作り、**モデルAからモデルBへ粒子で変形**させる
- 補間中はシェーダ内の乱流で散らす。定位置では実物メッシュへクロスフェード
- InstancedMesh で小片を1,000個以上/LineSegments で光の線
- ★前回「粒子が四角い塊になってモデルの形に見えない」という失敗があった。
**サンプリング点数を十分に取り(3万点以上)、点の大きさを小さく**して形が読めるようにしろ
【柱3】WebAudio で音を合成する(★今回の新要素)
- **音声ファイルは使わない。すべて OscillatorNode / BiquadFilter / GainNode 等で合成する**
- 画面に「♪ 音を出す」ボタンを置く(自動再生はブラウザが禁止するため)
- **章ごとに環境音が変わる**(スクロールに連動して音色・音量・フィルタが変化する)
- **スクロールを戻すと音も戻る**(音もスクロール量と1対1)
- リンクやボタンのホバー・クリックに短い効果音
- 音量スライダーと消音ボタンを必ず置く。初期音量は控えめに
━━━ 全章共通 ━━━
- **スクロール量と状態が1対1**。止めれば止まる。**上へ戻すと逆再生で巻き戻る**(最重要)
- 章ごとに"動きの種類"を変える(全章同じ回転は最大の減点)
- 固定表示して中身だけ進む区間を最低1つ/3Dはドラッグでも回せる
- 進捗バー・章インジケータを常時表示
- 375px と 1280px で横スクロールなし/日本語/prefers-reduced-motion 対応
- ローディング表示(テクスチャとglbの読み込み進捗%)
- 60fps を保つ(粒子は1ジオメトリに集約・毎フレーム再生成しない)
【お題】都心のフィットネスジムの **スクロール連動サイト**。
【支給3Dモデル】dumbbell.glb / kettlebell.glb / shoe.glb / shaker.glb / towel.glb
【支給写真】img/floor.jpg(ジムのラバーマット床)/img/night.jpg(高層階からの都市夜景)
img/concrete.jpg(打ちっぱなしコンクリート)/img/motion.jpg(オレンジの光跡)
【章構成(5章・動きの種類を全部変える)】
- 01 導入:**img/floor.jpg を床として敷き**、ダンベルがその上にせり上がる。**床に影が落ちる**。
壁は img/concrete.jpg。ブルームで金属が光る
- 02 特徴3点:ケトルベルが**落下→床でバウンド→静止**(減衰運動)。床の反射に映り込む
- 03 料金:シューズが**画面を横切り、カメラが追従**。背後を img/motion.jpg の光跡が視差で流れる
- 04 よくある質問:シェーカーが**分解→浮遊→再結合**
- 05 無料体験:**img/night.jpg を窓の夜景として奥に配置**し、タオルに god-ray が斜めに差す
【音(章ごと)】01 低い鼓動 → 02 落下の衝撃音 → 03 走行の風切り → 04 静かな環境音 → 05 開放的な広がり
【配色】チャコール × オレンジのアクセント。紫グラデーション禁止
【中身】キャッチコピー → 特徴3点 → 料金 → よくある質問 → 無料体験の申込
いちばん複雑な指示です。Reflectorの濡れた床・スプライン経路のカメラ・粒子変形・後処理・文字の3D化まで、技術を6分野に分けて指定しています。
【出力条件・厳守】 1. 出力は「単一のHTMLファイル」1つだけ(index.html)。同じフォルダの .glb と img/*.jpg を読む。 2. コードは省略禁止。「// 以下同様」「...(省略)」は禁止。全文を書ききる。 3. ★three.js 使用可(CDN可)。GLTFLoader・DRACOLoader・OrbitControls・EffectComposer・ UnrealBloomPass・BokehPass・AfterimagePass・MeshSurfaceSampler・ShaderMaterial・ TextureLoader・PMREMGenerator・Reflector を使ってよい。 ★スクロール演出のライブラリ(GSAP / ScrollTrigger / Lenis)は禁止。素のJSで書く。 ★音声ファイルの読み込みは禁止。WebAudio で合成する。 4. 起動時のコンソールエラーは0件。 5. 最後に「仕様チェックリスト」を表で出し ✅/❌ を自己申告(嘘の✅は最も減点)。 【お題】AIとITのメディア「ルーティンラボ」の **スクロール連動サイト**。 テーマは「**AI研究施設(ラボ)の内部を巡る**」。 主題は「**道具が変わると、毎日が変わる。**」=ここは"新しい道具が生まれる場所"。 ★★★これは発信者本人の顔になるサイト。**映像作品のような没入感**を狙え。 無難にまとめるのは最大の減点。**技術をふんだんに使って派手に**作れ。 【支給3Dモデル】 server.glb(サーバーラック)/ arm.glb(ロボットアーム)/ core.glb(球状リアクター)/ console.glb(制御コンソール)/ drone.glb(点検ドローン)/ capsule.glb(ガラス培養槽) 【支給写真】img/light.jpg(暖色のボケ玉・背景や光の重ねに使う) ━━━━ ★必ず全部実装する技術(1つでも欠けたら不合格)━━━━ 【A. 空間の作り込み】 - **Reflector(または同等の鏡面)で"濡れた床"を作る**。モデルと光が床に映り込む - **ボリュメトリックな光の筋(god-ray)**をシェーダで作り、暗闇に斜めに差す - **層状の霧**(FogExp2+シェーダ)で奥行きを出す。遠いものほど沈む - **PMREMGenerator で環境マップ**を作り、金属面に周囲を映り込ませる 【B. カメラワーク(★ここが"壮大"の本体)】 - **スクロールでカメラが空間内を移動する経路(CatmullRomCurve3 のスプライン)**を敷き、 スクロール量=経路上の位置 とする。**カメラが施設の中を飛ぶ** - カメラは**ダンピング**で滑らかに追従する(カクつかせない) - 章ごとに**注視点(lookAt)が別のモデルへ移る** - 1箇所で**スケールの落差**を作る(極小→画面を埋めるほど巨大、またはその逆) 【C. 粒子とジオメトリ生成】 - MeshSurfaceSampler で glb 表面から **5万点以上**サンプリングし、 **モデルAからモデルBへ粒子で変形**させる(崩壊→乱流→再構成) - **InstancedMesh で 2,000個以上**の小片(データの断片)を配置し、整列⇄拡散させる - **LineSegments で回路のような光の線**を走らせる - 自作のノイズ関数(simplex 等)をシェーダ内に書く 【D. 後処理】 - **UnrealBloomPass**(金属と光が滲む) - **BokehPass**(手前と奥がぼける) - **色収差とフィルムグレイン**を自作シェーダパスで足す(わずかに・やりすぎない) - **ビネット**で四隅を落とす 【E. 文字の3D化】 - 最終章で **"ROUTINE LABO" の文字を3D空間に立てる** (フォント読込は禁止なので、平面をグリッド状に並べて文字形にマスクする等、コードで解決) - カメラがその文字の**間を通り抜ける**か、文字が粒子から立ち上がる 【F. 音(WebAudio・合成のみ)】 - 「♪ 音を出す」ボタン+音量スライダー+消音ボタン - ★**鳴りっぱなしにしない**。**章の境目を越えた瞬間だけ 0.25〜0.6秒**の短い音を1回鳴らす (施設らしい金属質な「キュイン」「シュッ」。ノイズ+バンドパスのスイープで作る) - 同じ章の中では鳴らさない(デバウンスする) ━━━━ 全章共通 ━━━━ - **スクロール量と状態が1対1**。止めれば止まる。**上へ戻すと逆再生で巻き戻る**(最重要) - 章ごとに"動きの種類"を変える(全章同じ回転は最大の減点) - 3Dはドラッグでも回せる/進捗バー・章インジケータを常時表示 - 375px と 1280px で横スクロールなし/日本語/prefers-reduced-motion 対応 - ローディング表示(読み込み進捗%) - 60fps を保つ(粒子は1ジオメトリに集約・毎フレーム再生成しない) 【章構成(6章・動きの種類を全部変える)】 - 01 入口:暗闇の奥から**カメラが施設へ進入**。濡れた床に光が映る。server が奥に立つ - 02 観測:**console が眼前に迫り**、画面のグリッドが波打つ。InstancedMesh の断片が流れ出す - 03 解析:**core が粒子に崩れ、arm の形へ再構成**される(粒子変形の主役) - 04 試験:**capsule の内部へカメラが入り込む**(スケールの落差)。中で光が渦を巻く - 05 巡回:**drone がカメラと並走**しながら施設を横断。god-ray が何度も横切る - 06 発信:全粒子が収束し **"ROUTINE LABO" の文字**が立ち上がる。カメラが通り抜けて白へ 【音(章ごと)】01 低い起動音 → 02 電子的な短音 → 03 崩れる砂 → 04 密閉音 → 05 通過する風 → 06 開放する和音 【配色】ほぼ黒の空間 × 金属のグレー × **アンバー1色**のアクセント。紫グラデーション禁止 【中身】施設の紹介ではなく**メディアの紹介**として読めること: テーマの導入 → 発信しているもの3点 → 動画/ブログ/SNSへの導線 → 公式LINEへの導線