0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SPZビューワーつくーる(Vite + React + TS)

Posted at

はじめに

SPZ形式の3Dモデルを表示するアプリを作りました

開発環境

  • MacBook Air M1, 2020
  • Cursor 2.1.50
  • nvm 0.39.7
  • Node.js 22.4.0

フォルダ構成

frontend: Vite + React + TypeScript のフロントエンド

my-spz-viewer/
├── README.md                    # このファイル
└── frontend/                    # フロントエンドアプリケーション
    ├── index.html              # HTMLエントリーポイント
    ├── package.json            # 依存関係とスクリプト
    ├── vite.config.ts          # Vite設定ファイル
    ├── tsconfig.json           # TypeScript設定
    ├── tsconfig.node.json      # Node.js用TypeScript設定
    ├── .eslintrc.cjs           # ESLint設定
    ├── .gitignore              # Git除外設定
    └── src/                    # ソースコード
        ├── main.tsx            # Reactエントリーポイント
        ├── App.tsx             # メインアプリケーションコンポーネント
        ├── App.css             # アプリケーションスタイル
        ├── index.css           # グローバルスタイル
        └── components/         # Reactコンポーネント
            └── SplatViewerR3F.tsx  # SPZビューアコンポーネント(React Three Fiber統合)

導入

💬 splat形式のファイルをvite+react+tsで表示する方法

  1. 既存ライブラリ(gaussian-splats-3d / @sparkjsdev/spark / @zappar/three-gaussian-splat のどれか)を使ってサンプル動かしたい — 使いたいライブラリ名を指定して下さい。
  2. 「自前で PLY をパースして Three.js に反映」する最低限の parser を出してほしい(簡易版)。

💬 既存ライブラリ
A: @mkkellogg/gaussian-splats-3d を使った実際に動く最小構成プロジェクト(Vite の package.json、main.tsx、コンポーネント一式)をそのまま出します。
B: @sparkjsdev/spark を使った導入+ビルド手順つきの実例(WASM ビルド対応、SPZ を読み込む完全サンプル)を作ります。

💬 B: @sparkjsdev/spark を使った導入+ビルド手順つきの実例(WASM ビルド対応、SPZ を読み込む完全サンプル)を作ります。

いい選択です。`@sparkjsdev/spark`(以降「Spark」)は **SPZ / PLY / SPLAT 等のスプラット形式をブラウザ上で高速にレンダリング**するための Three.js 向けライブラリで、WASM(Rust)コンポーネントを持つため大きめデータにも強いです。以下は **Vite + React + TypeScript** プロジェクトに Spark を組み込み、WASM ビルドを含めて SPZ を読み込む「実行できる」手順とサンプルコードです。まず流れを示し、その後に具体的なコマンドとコードを載せます。主要なポイントはドキュメント・公式リポジトリに合わせてあります。([GitHub][1])

---

# 全体の流れ(要点)

1. Vite + React + TS のプロジェクトを作る。
2. 必要パッケージを入れる:`three``@react-three/fiber`(任意だが推奨)、`@sparkjsdev/spark`。([sparkjs.dev][2])
3. まず `npm install @sparkjsdev/spark` で済むか試す(公開パッケージに prebuilt な WASM が含まれていることが多い)。動かなければ(例:dev ブランチを使う/最新を手元でビルドしたい場合)Spark のソースをクローンして `npm run build`(内部で Rust → Wasm のビルドが走る)を実行。Rust が必要。([GitHub][1])
4. React 側では Three.js(あるいは react-three-fiber)と統合し、`SplatMesh`(高レベルなスプラットオブジェクト)や `SparkRenderer` をシーンに追加して `.spz` / `.ply` を読み込む。ドキュメントの `new SplatMesh({ url })` が最も簡単。([sparkjs.dev][2])

---

# 環境準備コマンド(例)

ターミナルで順に実行します。

1. Vite プロジェクト作成(TypeScript + React)

```bash
npm create vite@latest my-splat-app -- --template react-ts
cd my-splat-app
```

2. 依存インストール

```bash
npm install three @react-three/fiber @react-three/drei
npm install @sparkjsdev/spark
```

まずはこの状態で動かしてみてください。`@sparkjsdev/spark` が npm 経由でそのまま動くケースが多いです。([sparkjs.dev][2])

3. (必要なら)ローカルで Spark をビルドする — Rust が必要

* Rust を入れていない場合(推奨: rustup)

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# follow prompts, then restart shell
```

* Spark ソースをクローンしてビルド(WASM を含む)

```bash
git clone https://github.com/sparkjsdev/spark.git
cd spark
npm install
npm run build    # README にあるビルド手順: wasm 部分は npm run build:wasm 等で個別実行可能
# ビルド後、ローカルパッケージをプロジェクトに追加する場合:
# from your app folder:
# npm add ../path/to/spark   (or use npm link)
```

`npm run build` は内部で Rust → Wasm のビルドを呼びます(ローカルで dev 実行や最新ソースを利用したい場合に必要)。([GitHub][1])

---

# 実例コード(最小限で動く — React Three Fiber を使う)

以下は `@react-three/fiber` を使う例。`SplatMesh` を URL から読み込んでシーンに追加します。ファイル名は `src/components/SplatViewerR3F.tsx` としてください。

```tsx
// src/components/SplatViewerR3F.tsx
import React, { useEffect } from "react";
import { Canvas, useThree } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import * as THREE from "three";

// Spark の型は any にしておく(必要なら型定義を追加)
import { SplatMesh as SparkSplatMesh, SparkRenderer as SparkRendererClass } from "@sparkjsdev/spark";

function SparkScene({ url }: { url: string }) {
  const { scene, gl, camera } = useThree();

  useEffect(() => {
    let splatObj: THREE.Object3D | null = null;
    let sparkRenderer: any = null;

    (async () => {
      // SplatMesh を URL から作る(公式ドキュメントの使い方)
      // @sparkjsdev/spark の export をそのまま使えるはず
      const SplatMesh: any = (SparkSplatMesh as any) ?? (await import("@sparkjsdev/spark")).SplatMesh;
      const SparkRenderer: any = (SparkRendererClass as any) ?? (await import("@sparkjsdev/spark")).SparkRenderer;

      // SparkRenderer を scene に追加(任意。自動生成もされるが明示的に作る例)
      sparkRenderer = new SparkRenderer({ renderer: gl }); // ドキュメント参照
      scene.add(sparkRenderer);

      // SplatMesh の作成(url オプションでロード)
      splatObj = new SplatMesh({ url }); // URL はCORS対応済みであること
      splatObj.position.set(0, 0, 0);
      scene.add(splatObj);
    })();

    return () => {
      if (splatObj) scene.remove(splatObj);
      if (sparkRenderer) scene.remove(sparkRenderer);
    };
  }, [scene, gl, url]);

  return null;
}

export default function SplatViewerR3F({ url }: { url: string }) {
  return (
    <div style={{ width: "100%", height: "100vh" }}>
      <Canvas camera={{ position: [0, 0.5, 2], fov: 60 }}>
        <ambientLight intensity={0.9} />
        <SparkScene url={url} />
        <OrbitControls />
      </Canvas>
    </div>
  );
}
```

使い方(App.tsx など):

```tsx
import React from "react";
import SplatViewerR3F from "./components/SplatViewerR3F";

function App() {
  return <SplatViewerR3F url="https://sparkjs.dev/assets/splats/butterfly.spz" />;
}

export default App;
```

上の `butterfly.spz` は Spark のドキュメントで使われているデモ資産の一例です(CORS 設定されている公開アセットを使うか、自ホストならサーバ側で CORS を許可してください)。([sparkjs.dev][2])

---

# トラブルシューティング / 実務上の注意

* **WASM が見つからない/ロード失敗**`@sparkjsdev/spark` を npm で入れた場合は通常 prebuilt が含まれているが、開発版を取り込んだり local build したときは `npm run build`(Rust 必須)を実行して Wasm を生成する必要があります。エラーメッセージに `wasm` が含まれている場合はローカルビルドを試してください。([GitHub][1])
* **CORS**:外部 URL の SPZ を直接 `SplatMesh({ url })` に渡す場合、サーバが CORS を許可している必要があります。自分でホストするなら `Access-Control-Allow-Origin: *` 等を設定してください。
* **大きなファイル**:SPZ は圧縮フォーマットで小さいが、それでも数十〜数百MB のデータはブラウザ負荷が高いです。必要なら LOD・ストリーミング・オンデマンド読み込みを検討してください。([GitHub][3])

---

# 参考(公式ドキュメント・リポジトリ)

* Spark GitHub(README / ビルド手順). ([GitHub][1])
* Spark ドキュメント(Getting Started / SplatMesh) — `new SplatMesh({ url })` の使用例あり。([sparkjs.dev][2])
* React + r3f example(公式の `spark-react-r3f` サンプル) — r3f と組む場合の参考に。([GitHub][4])

---

必要なら次を即出します(どれか選んでください):

* 1. 上の手順どおりに動く **最小リポジトリの雛形**`package.json`, `vite.config.ts`, `src/main.tsx`, `src/App.tsx`, `src/components/SplatViewerR3F.tsx` を丸ごと)をそのまま貼る。
* 2. `npm run build`(Rust/WASM)で出る典型的なエラーとその対策集(Rust のインストール/wasm-pack の使い方/PATH の設定など)。
* 3. あなたの手元の `.spz` ファイル(あるいは公開 URL)があるなら、それを読み込むための最適な CORS・ホスティングの設定例(nginx / static server)。

どれにしますか?選ばなければまず **1)** の最小リポジトリ雛形をそのまま出します。

[1]: https://github.com/sparkjsdev/spark?utm_source=chatgpt.com "An advanced 3D Gaussian Splatting renderer for THREE.js"
[2]: https://sparkjs.dev/docs/?utm_source=chatgpt.com "Getting Started"
[3]: https://github.com/nianticlabs/spz?utm_source=chatgpt.com "GitHub - nianticlabs/spz: File format for 3D Gaussian splats. ..."
[4]: https://github.com/sparkjsdev/spark-react-r3f?utm_source=chatgpt.com "sparkjsdev/spark-react-r3f"

💬 frontendにspzを表示するアプリを実装して

  • package.jsonとvite設定ファイルを作成
  • TypeScript設定ファイルを作成
  • HTMLエントリーポイントとスタイルファイルを作成
  • Reactアプリのメインコンポーネントを作成
  • SPZビューアコンポーネントを作成
  • その他の設定ファイル(.gitignore等)を作成

💬 下記のエラー文を貼り付け

three.module.js?v=0385234b:53034 WARNING: Multiple instances of Three.js being imported.
(anonymous) @ three.module.js?v=0385234b:53034Understand this warning
chunk-GX6MTTAZ.js?v=0385234b:48272 SPZファイルの読み込みに失敗しました: TypeError: THREE.Matrix2 is not a constructor
    at _SparkRenderer.makeUniforms (spark.module.js?v=0385234b:10503:29)
    at new _SparkRenderer (spark.module.js?v=0385234b:10375:37)
    at loadSplat (SplatViewerR3F.tsx:43:31)
console.error @ chunk-GX6MTTAZ.js?v=0385234b:48272Understand this error
spark.module.js?v=0385234b:598 `WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:
 TypeError: Failed to execute 'compile' on 'WebAssembly': HTTP status code is not ok
__wbg_load @ spark.module.js?v=0385234b:598Understand this warning
spark.module.js?v=0385234b:605 Uncaught (in promise) CompileError: WebAssembly.instantiate(): BufferSource argument is empty
    at __wbg_load (spark.module.js?v=0385234b:605:30)
    at async __wbg_init (spark.module.js?v=0385234b:712:32)
    at async _SplatMesh.staticInitialize (spark.module.js?v=0385234b:7262:5)
  1. vite.config.ts - WASMファイルの処理を追加
  2. package.json - Three.jsのバージョンを調整
  3. src/main.tsx - Three.jsのグローバル設定
  4. src/components/SplatViewerR3F.tsx - エラーハンドリング改善
  5. index.html - 不要な参照を削除

💬 下記のエラー文を貼り付け

SplatViewerR3F.tsx:75 SPZファイルの読み込みに失敗しました: TypeError: THREE.Matrix2 is not a constructor
    at _SparkRenderer.makeUniforms (spark.module.js?v=51124b03:10503:29)
    at new _SparkRenderer (spark.module.js?v=51124b03:10375:37)
    at loadSplat (SplatViewerR3F.tsx:61:31)
console.error @ chunk-FPLVK4TI.js?v=51124b03:17705
loadSplat @ SplatViewerR3F.tsx:75
await in loadSplat
(anonymous) @ SplatViewerR3F.tsx:80
commitHookEffectListMount @ chunk-FPLVK4TI.js?v=51124b03:10911
commitPassiveMountOnFiber @ chunk-FPLVK4TI.js?v=51124b03:12219
commitPassiveMountEffects_complete @ chunk-FPLVK4TI.js?v=51124b03:12191
commitPassiveMountEffects_begin @ chunk-FPLVK4TI.js?v=51124b03:12181
commitPassiveMountEffects @ chunk-FPLVK4TI.js?v=51124b03:12171
flushPassiveEffectsImpl @ chunk-FPLVK4TI.js?v=51124b03:13939
flushPassiveEffects @ chunk-FPLVK4TI.js?v=51124b03:13902
performSyncWorkOnRoot @ chunk-FPLVK4TI.js?v=51124b03:13305
flushSyncCallbacks @ chunk-FPLVK4TI.js?v=51124b03:2766
commitRootImpl @ chunk-FPLVK4TI.js?v=51124b03:13887
commitRoot @ chunk-FPLVK4TI.js?v=51124b03:13743
finishConcurrentRender @ chunk-FPLVK4TI.js?v=51124b03:13242
performConcurrentWorkOnRoot @ chunk-FPLVK4TI.js?v=51124b03:13155
workLoop @ chunk-FPLVK4TI.js?v=51124b03:274
flushWork @ chunk-FPLVK4TI.js?v=51124b03:253
performWorkUntilDeadline @ chunk-FPLVK4TI.js?v=51124b03:461Understand this error
SplatViewerR3F.tsx:76 エラー詳細: TypeError: THREE.Matrix2 is not a constructor
    at _SparkRenderer.makeUniforms (http://localhost:3000/node_modules/@sparkjsdev/spark/dist/spark.module.js?v=51124b03:10503:29)
    at new _SparkRenderer (http://localhost:3000/node_modules/@sparkjsdev/spark/dist/spark.module.js?v=51124b03:10375:37)
    at loadSplat (http://localhost:3000/src/components/SplatViewerR3F.tsx:54:31)
console.error @ chunk-FPLVK4TI.js?v=51124b03:17705
loadSplat @ SplatViewerR3F.tsx:76
await in loadSplat
(anonymous) @ SplatViewerR3F.tsx:80
commitHookEffectListMount @ chunk-FPLVK4TI.js?v=51124b03:10911
commitPassiveMountOnFiber @ chunk-FPLVK4TI.js?v=51124b03:12219
commitPassiveMountEffects_complete @ chunk-FPLVK4TI.js?v=51124b03:12191
commitPassiveMountEffects_begin @ chunk-FPLVK4TI.js?v=51124b03:12181
commitPassiveMountEffects @ chunk-FPLVK4TI.js?v=51124b03:12171
flushPassiveEffectsImpl @ chunk-FPLVK4TI.js?v=51124b03:13939
flushPassiveEffects @ chunk-FPLVK4TI.js?v=51124b03:13902
performSyncWorkOnRoot @ chunk-FPLVK4TI.js?v=51124b03:13305
flushSyncCallbacks @ chunk-FPLVK4TI.js?v=51124b03:2766
commitRootImpl @ chunk-FPLVK4TI.js?v=51124b03:13887
commitRoot @ chunk-FPLVK4TI.js?v=51124b03:13743
finishConcurrentRender @ chunk-FPLVK4TI.js?v=51124b03:13242
performConcurrentWorkOnRoot @ chunk-FPLVK4TI.js?v=51124b03:13155
workLoop @ chunk-FPLVK4TI.js?v=51124b03:274
flushWork @ chunk-FPLVK4TI.js?v=51124b03:253
performWorkUntilDeadline @ chunk-FPLVK4TI.js?v=51124b03:461Understand this error
spark.module.js?v=51124b03:598 `WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:
 TypeError: Failed to execute 'compile' on 'WebAssembly': HTTP status code is not ok
__wbg_load @ spark.module.js?v=51124b03:598
await in __wbg_load
__wbg_init @ spark.module.js?v=51124b03:712
await in __wbg_init
staticInitialize @ spark.module.js?v=51124b03:7262
(anonymous) @ spark.module.js?v=51124b03:7619Understand this warning
spark.module.js?v=51124b03:605 Uncaught (in promise) CompileError: WebAssembly.instantiate(): BufferSource argument is empty
    at __wbg_load (spark.module.js?v=51124b03:605:30)
    at async __wbg_init (spark.module.js?v=51124b03:712:32)
    at async _SplatMesh.staticInitialize (spark.module.js?v=51124b03:7262:5)
  1. vite.config.ts - CORSヘッダーを削除、Three.jsのエイリアスを追加
  2. package.json - Three.jsのバージョンを調整
  3. src/components/SplatViewerR3F.tsx - デバッグ情報とエラーハンドリングを改善

💬 web検索して確認して

  • @sparkjsdev/sparkの公式リポジトリを確認
  • Three.jsのバージョンを試行

💬 最新版にしてみよう

更新内容

  • three: ^0.156.0 → ^0.175.0(最新版)
  • @types/three: ^0.156.0 → ^0.175.0(型定義も更新)
  • @sparkjsdev/spark: ^0.1.0 → ^0.1.7(最新版)

💬 下記のエラー文を貼り付け

spark.module.js?v=1fb0046d:598 `WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:
 TypeError: Failed to execute 'compile' on 'WebAssembly': HTTP status code is not ok
__wbg_load @ spark.module.js?v=1fb0046d:598
await in __wbg_load
__wbg_init @ spark.module.js?v=1fb0046d:712
await in __wbg_init
staticInitialize @ spark.module.js?v=1fb0046d:7262
(anonymous) @ spark.module.js?v=1fb0046d:7619Understand this warning
spark.module.js?v=1fb0046d:605 Uncaught (in promise) CompileError: WebAssembly.instantiate(): BufferSource argument is empty
    at __wbg_load (spark.module.js?v=1fb0046d:605:30)
    at async __wbg_init (spark.module.js?v=1fb0046d:712:32)
    at async _SplatMesh.staticInitialize (spark.module.js?v=1fb0046d:7262:5)
  • server.headersにCORSヘッダーを追加(WASM読み込みに必要)
  • worker設定を追加(WASMがワーカーで使用される場合)

💬 できました。ファイルからも読み込めるようにして下さい。

  • App.tsx
  • App.css
  • SplatViewerR3F.tsx

実行

実行してみましょう

cd frontend
npm install
npm run dev

http://localhost:5173 にアクセス

お疲れ様でした。

リポジトリはこちら

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?