@gradio/model3d 0.12.1 → 0.12.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @gradio/model3d
2
2
 
3
+ ## 0.12.2-beta.1
4
+
5
+ ### Features
6
+
7
+ - [#9187](https://github.com/gradio-app/gradio/pull/9187) [`5bf00b7`](https://github.com/gradio-app/gradio/commit/5bf00b7524ebf399b48719120a49d15bb21bd65c) - make all component SSR compatible. Thanks @pngwn!
8
+
9
+ ### Dependency updates
10
+
11
+ - @gradio/atoms@0.8.1-beta.1
12
+ - @gradio/icons@0.8.0-beta.1
13
+ - @gradio/statustracker@0.8.0-beta.1
14
+ - @gradio/utils@0.7.0-beta.1
15
+ - @gradio/client@1.6.0-beta.1
16
+ - @gradio/upload@0.12.4-beta.1
17
+ - @gradio/wasm@0.13.1-beta.1
18
+
19
+ ## 0.12.2-beta.0
20
+
21
+ ### Fixes
22
+
23
+ - [#9163](https://github.com/gradio-app/gradio/pull/9163) [`2b6cbf2`](https://github.com/gradio-app/gradio/commit/2b6cbf25908e42cf027324e54ef2cc0baad11a91) - fix exports and generate types. Thanks @pngwn!
24
+
25
+ ### Dependency updates
26
+
27
+ - @gradio/utils@0.7.0-beta.0
28
+ - @gradio/statustracker@0.8.0-beta.0
29
+ - @gradio/atoms@0.8.1-beta.0
30
+ - @gradio/client@1.6.0-beta.0
31
+ - @gradio/icons@0.8.0-beta.0
32
+ - @gradio/upload@0.12.4-beta.0
33
+ - @gradio/wasm@0.13.1-beta.0
34
+
3
35
  ## 0.12.1
4
36
 
5
37
  ### Features
package/Index.svelte CHANGED
@@ -41,6 +41,7 @@
41
41
  export let interactive: boolean;
42
42
 
43
43
  let dragging = false;
44
+ const is_browser = typeof window !== "undefined";
44
45
  </script>
45
46
 
46
47
  {#if !interactive}
@@ -63,7 +64,7 @@
63
64
  on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
64
65
  />
65
66
 
66
- {#if value}
67
+ {#if value && is_browser}
67
68
  <Model3D
68
69
  {value}
69
70
  i18n={gradio.i18n}
@@ -0,0 +1,18 @@
1
+ <script>export let value;
2
+ export let type;
3
+ export let selected = false;
4
+ </script>
5
+
6
+ <div
7
+ class:table={type === "table"}
8
+ class:gallery={type === "gallery"}
9
+ class:selected
10
+ >
11
+ {value ? value : ""}
12
+ </div>
13
+
14
+ <style>
15
+ .gallery {
16
+ padding: var(--size-1) var(--size-2);
17
+ }
18
+ </style>
@@ -0,0 +1,18 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ value: string | null;
5
+ type: "gallery" | "table";
6
+ selected?: boolean | undefined;
7
+ };
8
+ events: {
9
+ [evt: string]: CustomEvent<any>;
10
+ };
11
+ slots: {};
12
+ };
13
+ export type ExampleProps = typeof __propDef.props;
14
+ export type ExampleEvents = typeof __propDef.events;
15
+ export type ExampleSlots = typeof __propDef.slots;
16
+ export default class Example extends SvelteComponent<ExampleProps, ExampleEvents, ExampleSlots> {
17
+ }
18
+ export {};
@@ -0,0 +1,130 @@
1
+ <script context="module">export { default as BaseModel3D } from "./shared/Model3D.svelte";
2
+ export { default as BaseModel3DUpload } from "./shared/Model3DUpload.svelte";
3
+ export { default as BaseExample } from "./Example.svelte";
4
+ </script>
5
+
6
+ <script>import Model3D from "./shared/Model3D.svelte";
7
+ import Model3DUpload from "./shared/Model3DUpload.svelte";
8
+ import { BlockLabel, Block, Empty, UploadText } from "@gradio/atoms";
9
+ import { File } from "@gradio/icons";
10
+ import { StatusTracker } from "@gradio/statustracker";
11
+ export let elem_id = "";
12
+ export let elem_classes = [];
13
+ export let visible = true;
14
+ export let value = null;
15
+ export let root;
16
+ export let display_mode = "solid";
17
+ export let clear_color;
18
+ export let loading_status;
19
+ export let label;
20
+ export let show_label;
21
+ export let container = true;
22
+ export let scale = null;
23
+ export let min_width = void 0;
24
+ export let gradio;
25
+ export let height = void 0;
26
+ export let zoom_speed = 1;
27
+ export let camera_position = [
28
+ null,
29
+ null,
30
+ null
31
+ ];
32
+ export let interactive;
33
+ let dragging = false;
34
+ const is_browser = typeof window !== "undefined";
35
+ </script>
36
+
37
+ {#if !interactive}
38
+ <Block
39
+ {visible}
40
+ variant={value === null ? "dashed" : "solid"}
41
+ border_mode={dragging ? "focus" : "base"}
42
+ padding={false}
43
+ {elem_id}
44
+ {elem_classes}
45
+ {container}
46
+ {scale}
47
+ {min_width}
48
+ {height}
49
+ >
50
+ <StatusTracker
51
+ autoscroll={gradio.autoscroll}
52
+ i18n={gradio.i18n}
53
+ {...loading_status}
54
+ on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
55
+ />
56
+
57
+ {#if value && is_browser}
58
+ <Model3D
59
+ {value}
60
+ i18n={gradio.i18n}
61
+ {display_mode}
62
+ {clear_color}
63
+ {label}
64
+ {show_label}
65
+ {camera_position}
66
+ {zoom_speed}
67
+ />
68
+ {:else}
69
+ <!-- Not ideal but some bugs to work out before we can
70
+ make this consistent with other components -->
71
+
72
+ <BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
73
+
74
+ <Empty unpadded_box={true} size="large"><File /></Empty>
75
+ {/if}
76
+ </Block>
77
+ {:else}
78
+ <Block
79
+ {visible}
80
+ variant={value === null ? "dashed" : "solid"}
81
+ border_mode={dragging ? "focus" : "base"}
82
+ padding={false}
83
+ {elem_id}
84
+ {elem_classes}
85
+ {container}
86
+ {scale}
87
+ {min_width}
88
+ {height}
89
+ >
90
+ <StatusTracker
91
+ autoscroll={gradio.autoscroll}
92
+ i18n={gradio.i18n}
93
+ {...loading_status}
94
+ on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
95
+ />
96
+
97
+ <Model3DUpload
98
+ {label}
99
+ {show_label}
100
+ {root}
101
+ {display_mode}
102
+ {clear_color}
103
+ {value}
104
+ {camera_position}
105
+ {zoom_speed}
106
+ on:change={({ detail }) => (value = detail)}
107
+ on:drag={({ detail }) => (dragging = detail)}
108
+ on:change={({ detail }) => gradio.dispatch("change", detail)}
109
+ on:clear={() => {
110
+ value = null;
111
+ gradio.dispatch("clear");
112
+ }}
113
+ on:load={({ detail }) => {
114
+ value = detail;
115
+ gradio.dispatch("upload");
116
+ }}
117
+ on:error={({ detail }) => {
118
+ loading_status = loading_status || {};
119
+ loading_status.status = "error";
120
+ gradio.dispatch("error", detail);
121
+ }}
122
+ i18n={gradio.i18n}
123
+ max_file_size={gradio.max_file_size}
124
+ upload={gradio.client.upload}
125
+ stream_handler={gradio.client.stream}
126
+ >
127
+ <UploadText i18n={gradio.i18n} type="file" />
128
+ </Model3DUpload>
129
+ </Block>
130
+ {/if}
@@ -0,0 +1,38 @@
1
+ import { SvelteComponent } from "svelte";
2
+ export { default as BaseModel3D } from "./shared/Model3D.svelte";
3
+ export { default as BaseModel3DUpload } from "./shared/Model3DUpload.svelte";
4
+ export { default as BaseExample } from "./Example.svelte";
5
+ import type { FileData } from "@gradio/client";
6
+ import type { LoadingStatus } from "@gradio/statustracker";
7
+ import type { Gradio } from "@gradio/utils";
8
+ declare const __propDef: {
9
+ props: {
10
+ elem_id?: string | undefined;
11
+ elem_classes?: string[] | undefined;
12
+ visible?: boolean | undefined;
13
+ value?: (null | FileData) | undefined;
14
+ root: string;
15
+ display_mode?: ("solid" | "point_cloud" | "wireframe") | undefined;
16
+ clear_color: [number, number, number, number];
17
+ loading_status: LoadingStatus;
18
+ label: string;
19
+ show_label: boolean;
20
+ container?: boolean | undefined;
21
+ scale?: (number | null) | undefined;
22
+ min_width?: number | undefined;
23
+ gradio: Gradio;
24
+ height?: number | undefined;
25
+ zoom_speed?: number | undefined;
26
+ camera_position?: [number | null, number | null, number | null] | undefined;
27
+ interactive: boolean;
28
+ };
29
+ events: {
30
+ [evt: string]: CustomEvent<any>;
31
+ };
32
+ slots: {};
33
+ };
34
+ export type IndexProps = typeof __propDef.props;
35
+ export type IndexEvents = typeof __propDef.events;
36
+ export type IndexSlots = typeof __propDef.slots;
37
+ export default class Index extends SvelteComponent<IndexProps, IndexEvents, IndexSlots> {
38
+ }
@@ -0,0 +1,177 @@
1
+ <script>import { onMount } from "svelte";
2
+ import * as BABYLON from "babylonjs";
3
+ import * as BABYLON_LOADERS from "babylonjs-loaders";
4
+ import { resolve_wasm_src } from "@gradio/wasm/svelte";
5
+ $: {
6
+ if (BABYLON_LOADERS.OBJFileLoader != void 0 && !BABYLON_LOADERS.OBJFileLoader.IMPORT_VERTEX_COLORS) {
7
+ BABYLON_LOADERS.OBJFileLoader.IMPORT_VERTEX_COLORS = true;
8
+ }
9
+ }
10
+ export let value;
11
+ export let display_mode;
12
+ export let clear_color;
13
+ export let camera_position;
14
+ export let zoom_speed;
15
+ export let pan_speed;
16
+ $:
17
+ url = value.url;
18
+ export let resolved_url = void 0;
19
+ let latest_url;
20
+ $: {
21
+ resolved_url = url;
22
+ if (url) {
23
+ latest_url = url;
24
+ const resolving_url = url;
25
+ resolve_wasm_src(url).then((resolved) => {
26
+ if (latest_url === resolving_url) {
27
+ resolved_url = resolved ?? void 0;
28
+ } else {
29
+ resolved && URL.revokeObjectURL(resolved);
30
+ }
31
+ });
32
+ }
33
+ }
34
+ let canvas;
35
+ let scene;
36
+ let engine;
37
+ let point_cloud_system = null;
38
+ let mounted = false;
39
+ onMount(() => {
40
+ engine = new BABYLON.Engine(canvas, true);
41
+ scene = new BABYLON.Scene(engine);
42
+ scene.createDefaultCameraOrLight();
43
+ scene.useRightHandedSystem = true;
44
+ scene.clearColor = scene.clearColor = new BABYLON.Color4(...clear_color);
45
+ engine.runRenderLoop(() => {
46
+ scene.render();
47
+ });
48
+ function onWindowResize() {
49
+ engine.resize();
50
+ }
51
+ window.addEventListener("resize", onWindowResize);
52
+ mounted = true;
53
+ return () => {
54
+ scene.dispose();
55
+ engine.dispose();
56
+ window.removeEventListener("resize", onWindowResize);
57
+ };
58
+ });
59
+ $:
60
+ mounted && load_model(resolved_url);
61
+ function load_model(url2) {
62
+ if (scene) {
63
+ scene.meshes.forEach((mesh) => {
64
+ mesh.dispose();
65
+ });
66
+ if (point_cloud_system) {
67
+ point_cloud_system.dispose();
68
+ point_cloud_system = null;
69
+ }
70
+ if (url2) {
71
+ BABYLON.SceneLoader.ShowLoadingScreen = false;
72
+ BABYLON.SceneLoader.Append(
73
+ url2,
74
+ "",
75
+ scene,
76
+ () => {
77
+ if (display_mode === "point_cloud") {
78
+ create_point_cloud(scene);
79
+ } else if (display_mode === "wireframe") {
80
+ create_wireframe(scene);
81
+ } else {
82
+ create_camera(scene, camera_position, zoom_speed, pan_speed);
83
+ }
84
+ },
85
+ void 0,
86
+ void 0,
87
+ "." + value.path.split(".").pop()
88
+ );
89
+ }
90
+ }
91
+ }
92
+ function create_camera(scene2, camera_position2, zoom_speed2, pan_speed2) {
93
+ scene2.createDefaultCamera(true, true, true);
94
+ var helperCamera = scene2.activeCamera;
95
+ if (camera_position2[0] !== null) {
96
+ helperCamera.alpha = BABYLON.Tools.ToRadians(camera_position2[0]);
97
+ }
98
+ if (camera_position2[1] !== null) {
99
+ helperCamera.beta = BABYLON.Tools.ToRadians(camera_position2[1]);
100
+ }
101
+ if (camera_position2[2] !== null) {
102
+ helperCamera.radius = camera_position2[2];
103
+ }
104
+ helperCamera.lowerRadiusLimit = 0.1;
105
+ const updateCameraSensibility = () => {
106
+ helperCamera.wheelPrecision = 250 / (helperCamera.radius * zoom_speed2);
107
+ helperCamera.panningSensibility = 1e4 * pan_speed2 / helperCamera.radius;
108
+ };
109
+ updateCameraSensibility();
110
+ helperCamera.attachControl(true);
111
+ helperCamera.onAfterCheckInputsObservable.add(updateCameraSensibility);
112
+ }
113
+ export function reset_camera_position(camera_position2, zoom_speed2, pan_speed2) {
114
+ if (scene) {
115
+ scene.removeCamera(scene.activeCamera);
116
+ create_camera(scene, camera_position2, zoom_speed2, pan_speed2);
117
+ }
118
+ }
119
+ function create_point_cloud(scene2) {
120
+ const meshes = scene2.meshes;
121
+ const pointPositions = [];
122
+ meshes.forEach((mesh) => {
123
+ if (mesh instanceof BABYLON.Mesh) {
124
+ const positions = mesh.getVerticesData(
125
+ BABYLON.VertexBuffer.PositionKind
126
+ );
127
+ if (positions) {
128
+ for (let i = 0; i < positions.length; i += 3) {
129
+ pointPositions.push(
130
+ new BABYLON.Vector3(
131
+ positions[i],
132
+ positions[i + 1],
133
+ positions[i + 2]
134
+ )
135
+ );
136
+ }
137
+ }
138
+ mesh.setEnabled(false);
139
+ }
140
+ });
141
+ point_cloud_system = new BABYLON.PointsCloudSystem(
142
+ "point_cloud_system",
143
+ 1,
144
+ scene2
145
+ );
146
+ point_cloud_system.addPoints(
147
+ pointPositions.length,
148
+ (particle, i) => {
149
+ particle.position = pointPositions[i];
150
+ particle.color = new BABYLON.Color4(
151
+ Math.random(),
152
+ Math.random(),
153
+ Math.random(),
154
+ 1
155
+ );
156
+ }
157
+ );
158
+ point_cloud_system.buildMeshAsync().then((mesh) => {
159
+ mesh.alwaysSelectAsActiveMesh = true;
160
+ create_camera(scene2, camera_position, zoom_speed, pan_speed);
161
+ });
162
+ }
163
+ function create_wireframe(scene2) {
164
+ scene2.meshes.forEach((mesh) => {
165
+ if (mesh instanceof BABYLON.Mesh) {
166
+ mesh.material = new BABYLON.StandardMaterial(
167
+ "wireframeMaterial",
168
+ scene2
169
+ );
170
+ mesh.material.wireframe = true;
171
+ }
172
+ create_camera(scene2, camera_position, zoom_speed, pan_speed);
173
+ });
174
+ }
175
+ </script>
176
+
177
+ <canvas bind:this={canvas}></canvas>
@@ -0,0 +1,25 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { FileData } from "@gradio/client";
3
+ declare const __propDef: {
4
+ props: {
5
+ value: FileData;
6
+ display_mode: "solid" | "point_cloud" | "wireframe";
7
+ clear_color: [number, number, number, number];
8
+ camera_position: [number | null, number | null, number | null];
9
+ zoom_speed: number;
10
+ pan_speed: number;
11
+ resolved_url?: string | undefined;
12
+ reset_camera_position?: ((camera_position: [number | null, number | null, number | null], zoom_speed: number, pan_speed: number) => void) | undefined;
13
+ };
14
+ events: {
15
+ [evt: string]: CustomEvent<any>;
16
+ };
17
+ slots: {};
18
+ };
19
+ export type Canvas3DProps = typeof __propDef.props;
20
+ export type Canvas3DEvents = typeof __propDef.events;
21
+ export type Canvas3DSlots = typeof __propDef.slots;
22
+ export default class Canvas3D extends SvelteComponent<Canvas3DProps, Canvas3DEvents, Canvas3DSlots> {
23
+ get reset_camera_position(): (camera_position: [number | null, number | null, number | null], zoom_speed: number, pan_speed: number) => void;
24
+ }
25
+ export {};
@@ -0,0 +1,103 @@
1
+ <script>import { onMount } from "svelte";
2
+ import * as SPLAT from "gsplat";
3
+ import { resolve_wasm_src } from "@gradio/wasm/svelte";
4
+ export let value;
5
+ export let zoom_speed;
6
+ export let pan_speed;
7
+ $:
8
+ url = value.url;
9
+ export let resolved_url = void 0;
10
+ let latest_url;
11
+ $: {
12
+ resolved_url = url;
13
+ if (url) {
14
+ latest_url = url;
15
+ const resolving_url = url;
16
+ resolve_wasm_src(url).then((resolved) => {
17
+ if (latest_url === resolving_url) {
18
+ resolved_url = resolved ?? void 0;
19
+ } else {
20
+ resolved && URL.revokeObjectURL(resolved);
21
+ }
22
+ });
23
+ }
24
+ }
25
+ let canvas;
26
+ let scene;
27
+ let camera;
28
+ let renderer = null;
29
+ let controls;
30
+ let mounted = false;
31
+ let frameId = null;
32
+ function reset_scene() {
33
+ if (frameId !== null) {
34
+ cancelAnimationFrame(frameId);
35
+ frameId = null;
36
+ }
37
+ if (renderer !== null) {
38
+ renderer.dispose();
39
+ renderer = null;
40
+ }
41
+ scene = new SPLAT.Scene();
42
+ camera = new SPLAT.Camera();
43
+ renderer = new SPLAT.WebGLRenderer(canvas);
44
+ controls = new SPLAT.OrbitControls(camera, canvas);
45
+ controls.zoomSpeed = zoom_speed;
46
+ controls.panSpeed = pan_speed;
47
+ if (!value) {
48
+ return;
49
+ }
50
+ let loading = false;
51
+ const load = async () => {
52
+ if (loading) {
53
+ console.error("Already loading");
54
+ return;
55
+ }
56
+ if (!resolved_url) {
57
+ throw new Error("No resolved URL");
58
+ }
59
+ loading = true;
60
+ if (resolved_url.endsWith(".ply")) {
61
+ await SPLAT.PLYLoader.LoadAsync(resolved_url, scene, void 0);
62
+ } else if (resolved_url.endsWith(".splat")) {
63
+ await SPLAT.Loader.LoadAsync(resolved_url, scene, void 0);
64
+ } else {
65
+ throw new Error("Unsupported file type");
66
+ }
67
+ loading = false;
68
+ };
69
+ const frame = () => {
70
+ if (!renderer) {
71
+ return;
72
+ }
73
+ if (loading) {
74
+ frameId = requestAnimationFrame(frame);
75
+ return;
76
+ }
77
+ controls.update();
78
+ renderer.render(scene, camera);
79
+ frameId = requestAnimationFrame(frame);
80
+ };
81
+ load();
82
+ frameId = requestAnimationFrame(frame);
83
+ }
84
+ onMount(() => {
85
+ if (value != null) {
86
+ reset_scene();
87
+ }
88
+ mounted = true;
89
+ return () => {
90
+ if (renderer) {
91
+ renderer.dispose();
92
+ }
93
+ };
94
+ });
95
+ $:
96
+ ({ path } = value || {
97
+ path: void 0
98
+ });
99
+ $:
100
+ canvas && mounted && path && reset_scene();
101
+ </script>
102
+
103
+ <canvas bind:this={canvas}></canvas>
@@ -0,0 +1,20 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { FileData } from "@gradio/client";
3
+ declare const __propDef: {
4
+ props: {
5
+ value: FileData;
6
+ zoom_speed: number;
7
+ pan_speed: number;
8
+ resolved_url?: string | undefined;
9
+ };
10
+ events: {
11
+ [evt: string]: CustomEvent<any>;
12
+ };
13
+ slots: {};
14
+ };
15
+ export type Canvas3DgsProps = typeof __propDef.props;
16
+ export type Canvas3DgsEvents = typeof __propDef.events;
17
+ export type Canvas3DgsSlots = typeof __propDef.slots;
18
+ export default class Canvas3Dgs extends SvelteComponent<Canvas3DgsProps, Canvas3DgsEvents, Canvas3DgsSlots> {
19
+ }
20
+ export {};
@@ -0,0 +1,124 @@
1
+ <script>import { BlockLabel, IconButton } from "@gradio/atoms";
2
+ import { File, Download, Undo } from "@gradio/icons";
3
+ import { dequal } from "dequal";
4
+ export let value;
5
+ export let display_mode = "solid";
6
+ export let clear_color = [0, 0, 0, 0];
7
+ export let label = "";
8
+ export let show_label;
9
+ export let i18n;
10
+ export let zoom_speed = 1;
11
+ export let pan_speed = 1;
12
+ export let camera_position = [
13
+ null,
14
+ null,
15
+ null
16
+ ];
17
+ let current_settings = { camera_position, zoom_speed, pan_speed };
18
+ let use_3dgs = false;
19
+ let Canvas3DGSComponent;
20
+ let Canvas3DComponent;
21
+ async function loadCanvas3D() {
22
+ const module = await import("./Canvas3D.svelte");
23
+ return module.default;
24
+ }
25
+ async function loadCanvas3DGS() {
26
+ const module = await import("./Canvas3DGS.svelte");
27
+ return module.default;
28
+ }
29
+ $:
30
+ if (value) {
31
+ use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
32
+ if (use_3dgs) {
33
+ loadCanvas3DGS().then((component) => {
34
+ Canvas3DGSComponent = component;
35
+ });
36
+ } else {
37
+ loadCanvas3D().then((component) => {
38
+ Canvas3DComponent = component;
39
+ });
40
+ }
41
+ }
42
+ let canvas3d;
43
+ function handle_undo() {
44
+ canvas3d?.reset_camera_position(camera_position, zoom_speed, pan_speed);
45
+ }
46
+ $: {
47
+ if (!dequal(current_settings.camera_position, camera_position) || current_settings.zoom_speed !== zoom_speed || current_settings.pan_speed !== pan_speed) {
48
+ canvas3d?.reset_camera_position(camera_position, zoom_speed, pan_speed);
49
+ current_settings = { camera_position, zoom_speed, pan_speed };
50
+ }
51
+ }
52
+ let resolved_url;
53
+ </script>
54
+
55
+ <BlockLabel
56
+ {show_label}
57
+ Icon={File}
58
+ label={label || i18n("3D_model.3d_model")}
59
+ />
60
+ {#if value}
61
+ <div class="model3D">
62
+ <div class="buttons">
63
+ {#if !use_3dgs}
64
+ <!-- Canvas3DGS doesn't implement the undo method (reset_camera_position) -->
65
+ <IconButton Icon={Undo} label="Undo" on:click={() => handle_undo()} />
66
+ {/if}
67
+ <a
68
+ href={resolved_url}
69
+ target={window.__is_colab__ ? "_blank" : null}
70
+ download={window.__is_colab__ ? null : value.orig_name || value.path}
71
+ >
72
+ <IconButton Icon={Download} label={i18n("common.download")} />
73
+ </a>
74
+ </div>
75
+
76
+ {#if use_3dgs}
77
+ <svelte:component
78
+ this={Canvas3DGSComponent}
79
+ bind:resolved_url
80
+ {value}
81
+ {zoom_speed}
82
+ {pan_speed}
83
+ />
84
+ {:else}
85
+ <svelte:component
86
+ this={Canvas3DComponent}
87
+ bind:this={canvas3d}
88
+ bind:resolved_url
89
+ {value}
90
+ {display_mode}
91
+ {clear_color}
92
+ {camera_position}
93
+ {zoom_speed}
94
+ {pan_speed}
95
+ />
96
+ {/if}
97
+ </div>
98
+ {/if}
99
+
100
+ <style>
101
+ .model3D {
102
+ display: flex;
103
+ position: relative;
104
+ width: var(--size-full);
105
+ height: var(--size-full);
106
+ border-radius: var(--block-radius);
107
+ overflow: hidden;
108
+ }
109
+ .model3D :global(canvas) {
110
+ width: var(--size-full);
111
+ height: var(--size-full);
112
+ object-fit: contain;
113
+ overflow: hidden;
114
+ }
115
+ .buttons {
116
+ display: flex;
117
+ position: absolute;
118
+ top: var(--size-2);
119
+ right: var(--size-2);
120
+ justify-content: flex-end;
121
+ gap: var(--spacing-sm);
122
+ z-index: var(--layer-5);
123
+ }
124
+ </style>
@@ -0,0 +1,26 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { FileData } from "@gradio/client";
3
+ import type { I18nFormatter } from "@gradio/utils";
4
+ declare const __propDef: {
5
+ props: {
6
+ value: FileData | null;
7
+ display_mode?: ("solid" | "point_cloud" | "wireframe") | undefined;
8
+ clear_color?: [number, number, number, number] | undefined;
9
+ label?: string | undefined;
10
+ show_label: boolean;
11
+ i18n: I18nFormatter;
12
+ zoom_speed?: number | undefined;
13
+ pan_speed?: number | undefined;
14
+ camera_position?: [number | null, number | null, number | null] | undefined;
15
+ };
16
+ events: {
17
+ [evt: string]: CustomEvent<any>;
18
+ };
19
+ slots: {};
20
+ };
21
+ export type Model3DProps = typeof __propDef.props;
22
+ export type Model3DEvents = typeof __propDef.events;
23
+ export type Model3DSlots = typeof __propDef.slots;
24
+ export default class Model3D extends SvelteComponent<Model3DProps, Model3DEvents, Model3DSlots> {
25
+ }
26
+ export {};
@@ -0,0 +1,135 @@
1
+ <script>import { createEventDispatcher, tick } from "svelte";
2
+ import { Upload, ModifyUpload } from "@gradio/upload";
3
+ import { BlockLabel } from "@gradio/atoms";
4
+ import { File } from "@gradio/icons";
5
+ export let value;
6
+ export let display_mode = "solid";
7
+ export let clear_color = [0, 0, 0, 0];
8
+ export let label = "";
9
+ export let show_label;
10
+ export let root;
11
+ export let i18n;
12
+ export let zoom_speed = 1;
13
+ export let pan_speed = 1;
14
+ export let max_file_size = null;
15
+ export let camera_position = [
16
+ null,
17
+ null,
18
+ null
19
+ ];
20
+ export let upload;
21
+ export let stream_handler;
22
+ async function handle_upload({
23
+ detail
24
+ }) {
25
+ value = detail;
26
+ await tick();
27
+ dispatch("change", value);
28
+ dispatch("load", value);
29
+ }
30
+ async function handle_clear() {
31
+ value = null;
32
+ await tick();
33
+ dispatch("clear");
34
+ dispatch("change");
35
+ }
36
+ let use_3dgs = false;
37
+ let Canvas3DGSComponent;
38
+ let Canvas3DComponent;
39
+ async function loadCanvas3D() {
40
+ const module = await import("./Canvas3D.svelte");
41
+ return module.default;
42
+ }
43
+ async function loadCanvas3DGS() {
44
+ const module = await import("./Canvas3DGS.svelte");
45
+ return module.default;
46
+ }
47
+ $:
48
+ if (value) {
49
+ use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
50
+ if (use_3dgs) {
51
+ loadCanvas3DGS().then((component) => {
52
+ Canvas3DGSComponent = component;
53
+ });
54
+ } else {
55
+ loadCanvas3D().then((component) => {
56
+ Canvas3DComponent = component;
57
+ });
58
+ }
59
+ }
60
+ let canvas3d;
61
+ async function handle_undo() {
62
+ canvas3d?.reset_camera_position(camera_position, zoom_speed, pan_speed);
63
+ }
64
+ const dispatch = createEventDispatcher();
65
+ let dragging = false;
66
+ $:
67
+ dispatch("drag", dragging);
68
+ </script>
69
+
70
+ <BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
71
+
72
+ {#if value === null}
73
+ <Upload
74
+ {upload}
75
+ {stream_handler}
76
+ on:load={handle_upload}
77
+ {root}
78
+ {max_file_size}
79
+ filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
80
+ bind:dragging
81
+ on:error
82
+ >
83
+ <slot />
84
+ </Upload>
85
+ {:else}
86
+ <div class="input-model">
87
+ <ModifyUpload
88
+ undoable={!use_3dgs}
89
+ on:clear={handle_clear}
90
+ {i18n}
91
+ on:undo={handle_undo}
92
+ absolute
93
+ />
94
+
95
+ {#if use_3dgs}
96
+ <svelte:component
97
+ this={Canvas3DGSComponent}
98
+ {value}
99
+ {zoom_speed}
100
+ {pan_speed}
101
+ />
102
+ {:else}
103
+ <svelte:component
104
+ this={Canvas3DComponent}
105
+ bind:this={canvas3d}
106
+ {value}
107
+ {display_mode}
108
+ {clear_color}
109
+ {camera_position}
110
+ {zoom_speed}
111
+ {pan_speed}
112
+ />
113
+ {/if}
114
+ </div>
115
+ {/if}
116
+
117
+ <style>
118
+ .input-model {
119
+ display: flex;
120
+ position: relative;
121
+ justify-content: center;
122
+ align-items: center;
123
+ width: var(--size-full);
124
+ height: var(--size-full);
125
+ border-radius: var(--block-radius);
126
+ overflow: hidden;
127
+ }
128
+
129
+ .input-model :global(canvas) {
130
+ width: var(--size-full);
131
+ height: var(--size-full);
132
+ object-fit: contain;
133
+ overflow: hidden;
134
+ }
135
+ </style>
@@ -0,0 +1,38 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { FileData, Client } from "@gradio/client";
3
+ import type { I18nFormatter } from "@gradio/utils";
4
+ declare const __propDef: {
5
+ props: {
6
+ value: null | FileData;
7
+ display_mode?: ("solid" | "point_cloud" | "wireframe") | undefined;
8
+ clear_color?: [number, number, number, number] | undefined;
9
+ label?: string | undefined;
10
+ show_label: boolean;
11
+ root: string;
12
+ i18n: I18nFormatter;
13
+ zoom_speed?: number | undefined;
14
+ pan_speed?: number | undefined;
15
+ max_file_size?: (number | null) | undefined;
16
+ camera_position?: [number | null, number | null, number | null] | undefined;
17
+ upload: Client["upload"];
18
+ stream_handler: Client["stream"];
19
+ };
20
+ events: {
21
+ error: CustomEvent<any>;
22
+ change: CustomEvent<FileData | null>;
23
+ clear: CustomEvent<undefined>;
24
+ drag: CustomEvent<boolean>;
25
+ load: CustomEvent<FileData>;
26
+ } & {
27
+ [evt: string]: CustomEvent<any>;
28
+ };
29
+ slots: {
30
+ default: {};
31
+ };
32
+ };
33
+ export type Model3DUploadProps = typeof __propDef.props;
34
+ export type Model3DUploadEvents = typeof __propDef.events;
35
+ export type Model3DUploadSlots = typeof __propDef.slots;
36
+ export default class Model3DUpload extends SvelteComponent<Model3DUploadProps, Model3DUploadEvents, Model3DUploadSlots> {
37
+ }
38
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/model3d",
3
- "version": "0.12.1",
3
+ "version": "0.12.2-beta.1",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -12,24 +12,35 @@
12
12
  "babylonjs-loaders": "^4.2.1",
13
13
  "dequal": "^2.0.2",
14
14
  "gsplat": "^1.0.5",
15
- "@gradio/atoms": "^0.8.0",
16
- "@gradio/client": "^1.5.1",
17
- "@gradio/icons": "^0.7.1",
18
- "@gradio/upload": "^0.12.3",
19
- "@gradio/statustracker": "^0.7.5",
20
- "@gradio/utils": "^0.6.0",
21
- "@gradio/wasm": "^0.13.0"
15
+ "@gradio/atoms": "^0.8.1-beta.1",
16
+ "@gradio/icons": "^0.8.0-beta.1",
17
+ "@gradio/statustracker": "^0.8.0-beta.1",
18
+ "@gradio/upload": "^0.12.4-beta.1",
19
+ "@gradio/wasm": "^0.13.1-beta.1",
20
+ "@gradio/utils": "^0.7.0-beta.1",
21
+ "@gradio/client": "^1.6.0-beta.1"
22
22
  },
23
23
  "devDependencies": {
24
- "@gradio/preview": "^0.11.0"
24
+ "@gradio/preview": "^0.11.1-beta.0"
25
25
  },
26
26
  "main_changeset": true,
27
27
  "main": "./Index.svelte",
28
28
  "exports": {
29
- ".": "./Index.svelte",
30
- "./example": "./Example.svelte",
29
+ ".": {
30
+ "gradio": "./Index.svelte",
31
+ "svelte": "./dist/Index.svelte",
32
+ "types": "./dist/Index.svelte.d.ts"
33
+ },
34
+ "./example": {
35
+ "gradio": "./Example.svelte",
36
+ "svelte": "./dist/Example.svelte",
37
+ "types": "./dist/Example.svelte.d.ts"
38
+ },
31
39
  "./package.json": "./package.json"
32
40
  },
41
+ "peerDependencies": {
42
+ "svelte": "^4.0.0"
43
+ },
33
44
  "repository": {
34
45
  "type": "git",
35
46
  "url": "git+https://github.com/gradio-app/gradio.git",