diff --git a/.changeset/silly-apples-wait.md b/.changeset/silly-apples-wait.md
new file mode 100644
index 000000000000..33bca2a0cd58
--- /dev/null
+++ b/.changeset/silly-apples-wait.md
@@ -0,0 +1,6 @@
+---
+"@gradio/model3d": minor
+"gradio": minor
+---
+
+feat:Lite: Wasm-compatible Model3D
diff --git a/js/model3D/package.json b/js/model3D/package.json
index d066ffb85f26..3f9ff60e9202 100644
--- a/js/model3D/package.json
+++ b/js/model3D/package.json
@@ -13,6 +13,7 @@
"@gradio/statustracker": "workspace:^",
"@gradio/upload": "workspace:^",
"@gradio/utils": "workspace:^",
+ "@gradio/wasm": "workspace:^",
"@types/babylon": "^6.16.6",
"babylonjs": "^4.2.1",
"babylonjs-loaders": "^4.2.1",
diff --git a/js/model3D/shared/Canvas3D.svelte b/js/model3D/shared/Canvas3D.svelte
new file mode 100644
index 000000000000..3279c59a1aba
--- /dev/null
+++ b/js/model3D/shared/Canvas3D.svelte
@@ -0,0 +1,149 @@
+
+
+
diff --git a/js/model3D/shared/Model3D.svelte b/js/model3D/shared/Model3D.svelte
index 8890fdb6561a..c127c11fb9c7 100644
--- a/js/model3D/shared/Model3D.svelte
+++ b/js/model3D/shared/Model3D.svelte
@@ -2,10 +2,7 @@
import type { FileData } from "@gradio/client";
import { BlockLabel, IconButton } from "@gradio/atoms";
import { File, Download, Undo } from "@gradio/icons";
- import { add_new_model, reset_camera_position } from "./utils";
- import { onMount } from "svelte";
- import * as BABYLON from "babylonjs";
- import * as BABYLON_LOADERS from "babylonjs-loaders";
+ import Canvas3D from "./Canvas3D.svelte";
import type { I18nFormatter } from "@gradio/utils";
import { dequal } from "dequal";
@@ -25,71 +22,20 @@
let current_settings = { camera_position, zoom_speed, pan_speed };
- $: {
- if (
- BABYLON_LOADERS.OBJFileLoader != undefined &&
- !BABYLON_LOADERS.OBJFileLoader.IMPORT_VERTEX_COLORS
- ) {
- BABYLON_LOADERS.OBJFileLoader.IMPORT_VERTEX_COLORS = true;
- }
- }
-
- let canvas: HTMLCanvasElement;
- let scene: BABYLON.Scene;
- let engine: BABYLON.Engine | null;
- let mounted = false;
-
- onMount(() => {
- engine = new BABYLON.Engine(canvas, true);
- window.addEventListener("resize", () => {
- engine?.resize();
- });
- mounted = true;
- });
-
- $: ({ path } = value || {
- path: undefined
- });
-
- $: canvas && mounted && path && dispose();
-
- function dispose(): void {
- if (scene && !scene.isDisposed) {
- scene.dispose();
- engine?.stopRenderLoop();
- engine?.dispose();
- engine = null;
- engine = new BABYLON.Engine(canvas, true);
- window.addEventListener("resize", () => {
- engine?.resize();
- });
- }
- if (engine !== null) {
- scene = add_new_model(
- canvas,
- scene,
- engine,
- value,
- clear_color,
- camera_position,
- zoom_speed,
- pan_speed
- );
- }
- }
+ let canvas3d: Canvas3D;
+ let resolved_url: string | undefined;
function handle_undo(): void {
- reset_camera_position(scene, camera_position, zoom_speed, pan_speed);
+ canvas3d.reset_camera_position(camera_position, zoom_speed, pan_speed);
}
$: {
if (
- scene &&
- (!dequal(current_settings.camera_position, camera_position) ||
- current_settings.zoom_speed !== zoom_speed ||
- current_settings.pan_speed !== pan_speed)
+ !dequal(current_settings.camera_position, camera_position) ||
+ current_settings.zoom_speed !== zoom_speed ||
+ current_settings.pan_speed !== pan_speed
) {
- reset_camera_position(scene, camera_position, zoom_speed, pan_speed);
+ canvas3d.reset_camera_position(camera_position, zoom_speed, pan_speed);
current_settings = { camera_position, zoom_speed, pan_speed };
}
}
@@ -105,7 +51,7 @@
-
+
{/if}
@@ -124,7 +78,7 @@
width: var(--size-full);
height: var(--size-full);
}
- canvas {
+ .model3D :global(canvas) {
width: var(--size-full);
height: var(--size-full);
object-fit: contain;
diff --git a/js/model3D/shared/Model3DUpload.svelte b/js/model3D/shared/Model3DUpload.svelte
index b4941e8acfb6..fd03c46c8488 100644
--- a/js/model3D/shared/Model3DUpload.svelte
+++ b/js/model3D/shared/Model3DUpload.svelte
@@ -1,10 +1,11 @@
@@ -123,7 +76,14 @@
on:undo={handle_undo}
absolute
/>
-
+
{/if}
@@ -137,7 +97,7 @@
height: var(--size-full);
}
- canvas {
+ .input-model :global(canvas) {
width: var(--size-full);
height: var(--size-full);
object-fit: contain;
diff --git a/js/model3D/shared/utils.ts b/js/model3D/shared/utils.ts
deleted file mode 100644
index 1511f7458dec..000000000000
--- a/js/model3D/shared/utils.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import type { FileData } from "@gradio/client";
-import * as BABYLON from "babylonjs";
-
-const create_camera = (
- scene: BABYLON.Scene,
- camera_position: [number | null, number | null, number | null],
- zoom_speed: number,
- pan_speed: number
-): void => {
- scene.createDefaultCamera(true, true, true);
- var helperCamera = scene.activeCamera! as BABYLON.ArcRotateCamera;
- if (camera_position[0] !== null) {
- helperCamera.alpha = BABYLON.Tools.ToRadians(camera_position[0]);
- }
- if (camera_position[1] !== null) {
- helperCamera.beta = BABYLON.Tools.ToRadians(camera_position[1]);
- }
- if (camera_position[2] !== null) {
- helperCamera.radius = camera_position[2];
- }
- helperCamera.lowerRadiusLimit = 0.1;
- const updateCameraSensibility = (): void => {
- helperCamera.wheelPrecision = 250 / (helperCamera.radius * zoom_speed);
- helperCamera.panningSensibility = (10000 * pan_speed) / helperCamera.radius;
- };
- updateCameraSensibility();
- helperCamera.attachControl(true);
- helperCamera.onAfterCheckInputsObservable.add(updateCameraSensibility);
-};
-
-export const add_new_model = (
- canvas: HTMLCanvasElement,
- scene: BABYLON.Scene,
- engine: BABYLON.Engine,
- value: FileData | null,
- clear_color: [number, number, number, number],
- camera_position: [number | null, number | null, number | null],
- zoom_speed: number,
- pan_speed: number
-): BABYLON.Scene => {
- if (scene && !scene.isDisposed && engine) {
- scene.dispose();
- engine.dispose();
- }
-
- engine = new BABYLON.Engine(canvas, true);
- scene = new BABYLON.Scene(engine);
- scene.createDefaultCameraOrLight();
- scene.clearColor = scene.clearColor = new BABYLON.Color4(...clear_color);
-
- engine.runRenderLoop(() => {
- scene.render();
- });
-
- window.addEventListener("resize", () => {
- engine.resize();
- });
-
- if (!value) return scene;
- let url: string;
-
- url = value.url!;
-
- BABYLON.SceneLoader.ShowLoadingScreen = false;
- BABYLON.SceneLoader.Append(
- url,
- "",
- scene,
- () => create_camera(scene, camera_position, zoom_speed, pan_speed),
- undefined,
- undefined,
- "." + value.path.split(".")[1]
- );
- return scene;
-};
-
-export const reset_camera_position = (
- scene: BABYLON.Scene,
- camera_position: [number | null, number | null, number | null],
- zoom_speed: number,
- pan_speed: number
-): void => {
- scene.removeCamera(scene.activeCamera!);
- create_camera(scene, camera_position, zoom_speed, pan_speed);
-};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 99c96ba87ed3..175bd7f142f5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1167,6 +1167,9 @@ importers:
'@gradio/utils':
specifier: workspace:^
version: link:../utils
+ '@gradio/wasm':
+ specifier: workspace:^
+ version: link:../wasm
'@types/babylon':
specifier: ^6.16.6
version: 6.16.6