# `@huggingface/usd-web-viewer`

[OpenUSD](https://openusd.org) di browser: komposisi USD dalam WebAssembly, dibangun di atas [openusd](https://github.com/mxpv/openusd) (Rust murni), dirender dengan [three.js](https://threejs.org). Membaca `.usd`, `.usda`, `.usdc` dan `.usdz`; pemuatan dijalankan dalam Web Worker.

```sh
npm install @huggingface/usd-web-viewer three
```

## Penggunaan

Penampil siap pakai (renderer, pencahayaan, kontrol orbit):

```js
import { createViewer } from '@huggingface/usd-web-viewer';

const viewer = createViewer(document.getElementById('viewer')); // a container element
const { info } = await viewer.load(
  'https://huggingface.co/datasets/Robotiq-Official/simready-assets/resolve/main/Robotiq_2F_85/simready_usd/Robotiq_2F_85.usda',
);
```

Atau ke dalam scene three.js Anda sendiri:

```js
import { loadUsd } from '@huggingface/usd-web-viewer';

const { root, complete, dispose } = await loadUsd(url);
scene.add(root); // a THREE.Group, Y-up, in meters
await complete; // textures stream in after the geometry
```

## Fisika dan sendi

`info` juga melaporkan apa yang ditulis oleh penulis stage untuk simulasi (UsdPhysics) dan label UsdSemantics-nya, sesuai dengan yang ditulis: tidak ada yang diestimasi. Massa dalam kilogram, densitas dalam kg/m³, inersia dalam kg·m², batas dan posisi sendi dalam derajat atau meter; posisi dan matriks berada di ruang stage, seperti mesh di bawah `root`.

```js
const { info, joints, setJointPositions, resetJointPositions, getJointPositions, getWorldMatrix } = await viewer.load(url);

info.physics.bodies; // rigid bodies: mass, center of mass, inertia, colliders, bodies fixed to them
info.physics.colliders; // shape, approximation (convexHull, sdf, ...), physics material
info.physics.materials; // density, friction, restitution
info.physics.joints; // revolute, prismatic, spherical, distance, fixed and generic joints with their limits and drives
info.physics.articulationRoots; // where articulations (bodies solved together, like a robot) start
info.physics.frames; // Xforms under a body, often points with no mesh, like a gripper's tip
info.labels; // e.g. { path: '/RootNode', taxonomy: 'wikidata_class', values: ['cabinet'] }
info.variantSelections; // e.g. { prim: '/Robotiq_2F_85', set: 'Physics', selection: 'Physx_parallel_grip' }
info.dependencies; // every layer and texture the stage read, with its size

joints; // the joints setJointPositions can move, e.g. to build sliders
setJointPositions({ '/Robotiq_2F_85/Robotiq_2F_85/Joints/finger_joint': 40 }); // revolute and prismatic joints, any number at once; what hangs from them and mimic joints follow
getJointPositions(); // where every revolute and prismatic joint is now
getWorldMatrix('/SO101/gripper/gripper_frame_link'); // where a body, frame or mesh under a body is now and which way it faces, as a THREE.Matrix4 in the scene; null if it is none of those
resetJointPositions(); // back to the authored pose
```

Posing bersifat kinematik saja (tanpa tabrakan atau gravitasi) dan cukup murah untuk setiap frame dari seretan slider atau perekaman.

## Opsi

`loadUsd(url, options)` dan `viewer.load(url, options)` menerima:

| Opsi                         | Default             |                                                                                 |
| ------------------------------ | ------------------- | ------------------------------------------------------------------------------- |
| `textures`                     | `'preview'`         | `'none'`, `'preview'` (warna dasar, peta data kecil, tanpa peta normal) atau `'full'` |
| `maxTextureSize`               | `1024`              | Sisi panjang dari tekstur yang didekode, dalam piksel                                        |
| `signal`                       |                     | Sebuah `AbortSignal`; pemuatan ditolak dengan `UsdLoadError` berkode `aborted`      |
| `onProgress`                   |                     | Dipanggil dengan stage dan `fraction` keseluruhan dari 0 hingga 1                     |
| `files`                        |                     | Muat file yang dijatuhkan atau dipilih alih-alih dari jaringan (lihat di bawah)                 |
| `wasmUrl`, `workerUrl`         | di samping paket | Tempat di mana biner WASM dan skrip worker disajikan                     |
| `maxConcurrentFetches`         | `16`                | Permintaan yang sedang berlangsung sekaligus                                                      |
| `maxLayerBytes`, `maxLayers`   | 768 MiB, 1024       | Batas unduhan layer                                                           |
| `maxTextureBytes`              | 512 MiB             | Batas unduhan tekstur                                                          |
| `maxTriangles`, `maxInstances` | 20M, 100,000        | Yang digambar paling banyak                                                           |

`createViewer(container, options)` menerima `background` (default transparan), `onContextLost` dan `onContextRestored` (dipanggil dengan reload dari model terakhir yang ditampilkan).

Gagal adalah `UsdLoadError` dengan `code` (`aborted`, `fetch`, `compose`, `worker`, `webgl`); apa pun yang tidak dapat ditampilkan secara akurat dicantumkan dalam `info.warnings`. Setiap opsi, error, dan warning memiliki tipe.

## Memuat file yang tidak tepercaya

- Permintaan dikirim seperti `<model-viewer>`: cookie hanya ke origin halaman itu sendiri (`credentials: 'same-origin'`), tanpa header kustom, tanpa referrer.
- Lapisan dan tekstur hanya diambil melalui http(s).
- Parsing berjalan di Rust yang dikompilasi ke WebAssembly, di dalam Web Worker.
- Setiap beban dibatasi: `maxLayerBytes` (768 MiB), `maxLayers` (1024), `maxTextureBytes` (512 MiB), `maxTriangles` (20M) dan `maxInstances` (100.000); gambar hingga 16384 px per sisi dan 8192 x 8192 px dalam area; prim bersarang hingga kedalaman 256 level; entri `.usdz` hingga 512 MiB masing-masing dan 1 GiB secara keseluruhan, disimpan tanpa kompresi.
- File yang tidak valid gagal dimuat dengan `UsdLoadError`.

## File lokal

Untuk menampilkan file yang dijatuhkan ke halaman atau dipilih dengan `<input type="file" webkitdirectory>`, berikan file tersebut sebagai `files`, dengan kunci berupa path mereka di dalam paket, lalu muat kunci dari lapisan root. Path relatif di dalam file dipecahkan satu sama lain; tidak ada yang diambil untuk path tersebut.

```js
const files = new Map([...input.files].map((file) => [file.webkitRelativePath || file.name, file]));
await viewer.load('chair/simready_usd/sm_chair.usd', { files });
```

## Bundlers

Worker dan biner WASM ditemukan dengan `new URL(..., import.meta.url)`, yang di-resolve dan di-emit oleh Vite, webpack, dan bundler lainnya. Dengan dev server Vite, kecuali paket dari pre-bundling dependensi:

```js
// vite.config.js
export default { optimizeDeps: { exclude: ['@huggingface/usd-web-viewer'] } };
```

Berlisensi MIT. Lisensi dari crate Rust yang dikompilasi ke dalam biner WASM terdapat di `THIRD_PARTY_LICENSES`.

