@gradio/model3d 0.16.0 → 0.16.2

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,32 @@
1
1
  # @gradio/model3d
2
2
 
3
+ ## 0.16.2
4
+
5
+ ### Fixes
6
+
7
+ - [#12800](https://github.com/gradio-app/gradio/pull/12800) [`7a1c321`](https://github.com/gradio-app/gradio/commit/7a1c321b6546ba05a353488f5133e8262c4a8a39) - Bump svelte/kit for security reasons. Thanks @freddyaboulton!
8
+ - [#12779](https://github.com/gradio-app/gradio/pull/12779) [`ea2d3e9`](https://github.com/gradio-app/gradio/commit/ea2d3e985a8b42d188e551f517c5825c00790628) - Migrate Audio + Upload + Atoms to Svelte 5. Thanks @dawoodkhan82!
9
+
10
+ ### Dependency updates
11
+
12
+ - @gradio/statustracker@0.12.2
13
+ - @gradio/atoms@0.20.1
14
+ - @gradio/utils@0.11.2
15
+ - @gradio/icons@0.15.1
16
+ - @gradio/upload@0.17.4
17
+ - @gradio/client@2.0.3
18
+
19
+ ## 0.16.1
20
+
21
+ ### Fixes
22
+
23
+ - [#12688](https://github.com/gradio-app/gradio/pull/12688) [`5206d47`](https://github.com/gradio-app/gradio/commit/5206d47b7730e6ffc8efd90d8157dd5388c18dc5) - Migrate Model3D to Svelte 5. Thanks @dawoodkhan82!
24
+
25
+ ### Dependency updates
26
+
27
+ - @gradio/utils@0.11.1
28
+ - @gradio/client@2.0.2
29
+
3
30
  ## 0.16.0
4
31
 
5
32
  ### Features
package/Index.svelte CHANGED
@@ -157,15 +157,15 @@
157
157
  root={gradio.shared.root}
158
158
  display_mode={gradio.props.display_mode}
159
159
  clear_color={gradio.props.clear_color}
160
- value={gradio.props.value}
160
+ bind:value={gradio.props.value}
161
161
  camera_position={gradio.props.camera_position}
162
162
  zoom_speed={gradio.props.zoom_speed}
163
163
  bind:uploading
164
- on:change={({ detail }) => handle_change(detail)}
165
- on:drag={({ detail }) => handle_drag(detail)}
166
- on:clear={handle_clear}
167
- on:load={({ detail }) => handle_load(detail)}
168
- on:error={({ detail }) => handle_error(detail)}
164
+ onchange={handle_change}
165
+ ondrag={handle_drag}
166
+ onclear={handle_clear}
167
+ onload={handle_load}
168
+ onerror={handle_error}
169
169
  i18n={gradio.i18n}
170
170
  max_file_size={gradio.shared.max_file_size}
171
171
  upload={(...args) => gradio.shared.client.upload(...args)}
package/dist/Index.svelte CHANGED
@@ -157,15 +157,15 @@
157
157
  root={gradio.shared.root}
158
158
  display_mode={gradio.props.display_mode}
159
159
  clear_color={gradio.props.clear_color}
160
- value={gradio.props.value}
160
+ bind:value={gradio.props.value}
161
161
  camera_position={gradio.props.camera_position}
162
162
  zoom_speed={gradio.props.zoom_speed}
163
163
  bind:uploading
164
- on:change={({ detail }) => handle_change(detail)}
165
- on:drag={({ detail }) => handle_drag(detail)}
166
- on:clear={handle_clear}
167
- on:load={({ detail }) => handle_load(detail)}
168
- on:error={({ detail }) => handle_error(detail)}
164
+ onchange={handle_change}
165
+ ondrag={handle_drag}
166
+ onclear={handle_clear}
167
+ onload={handle_load}
168
+ onerror={handle_error}
169
169
  i18n={gradio.i18n}
170
170
  max_file_size={gradio.shared.max_file_size}
171
171
  upload={(...args) => gradio.shared.client.upload(...args)}
@@ -5,19 +5,28 @@
5
5
 
6
6
  let BABYLON_VIEWER: typeof import("@babylonjs/viewer");
7
7
 
8
- export let value: FileData;
9
- export let display_mode: "solid" | "point_cloud" | "wireframe";
10
- export let clear_color: [number, number, number, number];
11
- export let camera_position: [number | null, number | null, number | null];
12
- export let zoom_speed: number;
13
- export let pan_speed: number;
8
+ let {
9
+ value,
10
+ display_mode,
11
+ clear_color,
12
+ camera_position,
13
+ zoom_speed,
14
+ pan_speed
15
+ }: {
16
+ value: FileData;
17
+ display_mode: "solid" | "point_cloud" | "wireframe";
18
+ clear_color: [number, number, number, number];
19
+ camera_position: [number | null, number | null, number | null];
20
+ zoom_speed: number;
21
+ pan_speed: number;
22
+ } = $props();
14
23
 
15
- $: url = value.url;
24
+ let url = $derived(value.url);
16
25
 
17
26
  let canvas: HTMLCanvasElement;
18
- let viewer: Viewer;
19
- let viewerDetails: Readonly<ViewerDetails>;
20
- let mounted = false;
27
+ let viewer = $state<Viewer>();
28
+ let viewerDetails = $state<Readonly<ViewerDetails>>();
29
+ let mounted = $state(false);
21
30
 
22
31
  onMount(() => {
23
32
  const initViewer = async (): Promise<void> => {
@@ -43,9 +52,14 @@
43
52
  };
44
53
  });
45
54
 
46
- $: mounted && load_model(url);
55
+ $effect(() => {
56
+ if (mounted) {
57
+ load_model(url);
58
+ }
59
+ });
47
60
 
48
61
  function setRenderingMode(pointsCloud: boolean, wireframe: boolean): void {
62
+ if (!viewerDetails) return;
49
63
  viewerDetails.scene.forcePointsCloud = pointsCloud;
50
64
  viewerDetails.scene.forceWireframe = wireframe;
51
65
  }
@@ -81,6 +95,7 @@
81
95
  zoom_speed: number,
82
96
  pan_speed: number
83
97
  ): void {
98
+ if (!viewerDetails) return;
84
99
  const camera = viewerDetails.camera;
85
100
  if (camera_position[0] !== null) {
86
101
  camera.alpha = (camera_position[0] * Math.PI) / 180;
@@ -101,7 +116,7 @@
101
116
  }
102
117
 
103
118
  export function reset_camera_position(): void {
104
- if (viewerDetails) {
119
+ if (viewerDetails && viewer) {
105
120
  viewer.resetCamera();
106
121
  }
107
122
  }
@@ -1,31 +1,15 @@
1
1
  import type { FileData } from "@gradio/client";
2
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
- $$bindings?: Bindings;
5
- } & Exports;
6
- (internal: unknown, props: Props & {
7
- $$events?: Events;
8
- $$slots?: Slots;
9
- }): Exports & {
10
- $set?: any;
11
- $on?: any;
12
- };
13
- z_$$bindings?: Bindings;
14
- }
15
- declare const Canvas3D: $$__sveltets_2_IsomorphicComponent<{
2
+ type $$ComponentProps = {
16
3
  value: FileData;
17
4
  display_mode: "solid" | "point_cloud" | "wireframe";
18
5
  clear_color: [number, number, number, number];
19
6
  camera_position: [number | null, number | null, number | null];
20
7
  zoom_speed: number;
21
8
  pan_speed: number;
22
- update_camera?: (camera_position: [number | null, number | null, number | null], zoom_speed: number, pan_speed: number) => void;
23
- reset_camera_position?: () => void;
24
- }, {
25
- [evt: string]: CustomEvent<any>;
26
- }, {}, {
9
+ };
10
+ declare const Canvas3D: import("svelte").Component<$$ComponentProps, {
27
11
  update_camera: (camera_position: [number | null, number | null, number | null], zoom_speed: number, pan_speed: number) => void;
28
12
  reset_camera_position: () => void;
29
- }, string>;
30
- type Canvas3D = InstanceType<typeof Canvas3D>;
13
+ }, "">;
14
+ type Canvas3D = ReturnType<typeof Canvas3D>;
31
15
  export default Canvas3D;
@@ -3,19 +3,25 @@
3
3
  import * as SPLAT from "gsplat";
4
4
  import type { FileData } from "@gradio/client";
5
5
 
6
- export let value: FileData;
7
- export let zoom_speed: number;
8
- export let pan_speed: number;
9
-
10
- $: url = value.url;
6
+ let {
7
+ value,
8
+ zoom_speed,
9
+ pan_speed
10
+ }: {
11
+ value: FileData;
12
+ zoom_speed: number;
13
+ pan_speed: number;
14
+ } = $props();
15
+
16
+ let url = $derived(value.url);
11
17
 
12
18
  let canvas: HTMLCanvasElement;
13
19
  let scene: SPLAT.Scene;
14
20
  let camera: SPLAT.Camera;
15
- let renderer: SPLAT.WebGLRenderer | null = null;
21
+ let renderer = $state<SPLAT.WebGLRenderer | null>(null);
16
22
  let controls: SPLAT.OrbitControls;
17
- let mounted = false;
18
- let frameId: number | null = null;
23
+ let mounted = $state(false);
24
+ let frameId = $state<number | null>(null);
19
25
 
20
26
  function reset_scene(): void {
21
27
  if (frameId !== null) {
@@ -92,11 +98,13 @@
92
98
  };
93
99
  });
94
100
 
95
- $: ({ path } = value || {
96
- path: undefined
97
- });
101
+ let path = $derived(value?.path);
98
102
 
99
- $: canvas && mounted && path && reset_scene();
103
+ $effect(() => {
104
+ if (canvas && mounted && path) {
105
+ reset_scene();
106
+ }
107
+ });
100
108
  </script>
101
109
 
102
110
  <canvas bind:this={canvas}></canvas>
@@ -1,23 +1,9 @@
1
1
  import type { FileData } from "@gradio/client";
2
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
- $$bindings?: Bindings;
5
- } & Exports;
6
- (internal: unknown, props: Props & {
7
- $$events?: Events;
8
- $$slots?: Slots;
9
- }): Exports & {
10
- $set?: any;
11
- $on?: any;
12
- };
13
- z_$$bindings?: Bindings;
14
- }
15
- declare const Canvas3DGS: $$__sveltets_2_IsomorphicComponent<{
2
+ type $$ComponentProps = {
16
3
  value: FileData;
17
4
  zoom_speed: number;
18
5
  pan_speed: number;
19
- }, {
20
- [evt: string]: CustomEvent<any>;
21
- }, {}, {}, string>;
22
- type Canvas3DGS = InstanceType<typeof Canvas3DGS>;
6
+ };
7
+ declare const Canvas3DGS: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type Canvas3DGS = ReturnType<typeof Canvas3DGS>;
23
9
  export default Canvas3DGS;
@@ -7,27 +7,36 @@
7
7
  import type Canvas3DGS from "./Canvas3DGS.svelte";
8
8
  import type Canvas3D from "./Canvas3D.svelte";
9
9
 
10
- export let value: FileData | null;
11
- export let display_mode: "solid" | "point_cloud" | "wireframe" = "solid";
12
- export let clear_color: [number, number, number, number] = [0, 0, 0, 0];
13
- export let label = "";
14
- export let show_label: boolean;
15
- export let i18n: I18nFormatter;
16
- export let zoom_speed = 1;
17
- export let pan_speed = 1;
18
- // alpha, beta, radius
19
- export let camera_position: [number | null, number | null, number | null] = [
20
- null,
21
- null,
22
- null
23
- ];
24
- export let has_change_history = false;
10
+ let {
11
+ value,
12
+ display_mode = "solid",
13
+ clear_color = [0, 0, 0, 0],
14
+ label = "",
15
+ show_label,
16
+ i18n,
17
+ zoom_speed = 1,
18
+ pan_speed = 1,
19
+ camera_position = [null, null, null],
20
+ has_change_history = false
21
+ }: {
22
+ value: FileData | null;
23
+ display_mode?: "solid" | "point_cloud" | "wireframe";
24
+ clear_color?: [number, number, number, number];
25
+ label?: string;
26
+ show_label: boolean;
27
+ i18n: I18nFormatter;
28
+ zoom_speed?: number;
29
+ pan_speed?: number;
30
+ camera_position?: [number | null, number | null, number | null];
31
+ has_change_history?: boolean;
32
+ } = $props();
25
33
 
26
- let current_settings = { camera_position, zoom_speed, pan_speed };
34
+ let current_settings = $state({ camera_position, zoom_speed, pan_speed });
35
+ let use_3dgs = $state(false);
36
+ let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
37
+ let Canvas3DComponent = $state<typeof Canvas3D>();
38
+ let canvas3d = $state<Canvas3D | undefined>();
27
39
 
28
- let use_3dgs = false;
29
- let Canvas3DGSComponent: typeof Canvas3DGS;
30
- let Canvas3DComponent: typeof Canvas3D;
31
40
  async function loadCanvas3D(): Promise<typeof Canvas3D> {
32
41
  const module = await import("./Canvas3D.svelte");
33
42
  return module.default;
@@ -36,25 +45,27 @@
36
45
  const module = await import("./Canvas3DGS.svelte");
37
46
  return module.default;
38
47
  }
39
- $: if (value) {
40
- use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
41
- if (use_3dgs) {
42
- loadCanvas3DGS().then((component) => {
43
- Canvas3DGSComponent = component;
44
- });
45
- } else {
46
- loadCanvas3D().then((component) => {
47
- Canvas3DComponent = component;
48
- });
48
+
49
+ $effect(() => {
50
+ if (value) {
51
+ use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
52
+ if (use_3dgs) {
53
+ loadCanvas3DGS().then((component) => {
54
+ Canvas3DGSComponent = component;
55
+ });
56
+ } else {
57
+ loadCanvas3D().then((component) => {
58
+ Canvas3DComponent = component;
59
+ });
60
+ }
49
61
  }
50
- }
62
+ });
51
63
 
52
- let canvas3d: Canvas3D | undefined;
53
64
  function handle_undo(): void {
54
65
  canvas3d?.reset_camera_position();
55
66
  }
56
67
 
57
- $: {
68
+ $effect(() => {
58
69
  if (
59
70
  !dequal(current_settings.camera_position, camera_position) ||
60
71
  current_settings.zoom_speed !== zoom_speed ||
@@ -63,7 +74,7 @@
63
74
  canvas3d?.update_camera(camera_position, zoom_speed, pan_speed);
64
75
  current_settings = { camera_position, zoom_speed, pan_speed };
65
76
  }
66
- }
77
+ });
67
78
  </script>
68
79
 
69
80
  <BlockLabel
@@ -79,7 +90,7 @@
79
90
  <IconButton
80
91
  Icon={Undo}
81
92
  label="Undo"
82
- on:click={() => handle_undo()}
93
+ onclick={() => handle_undo()}
83
94
  disabled={!has_change_history}
84
95
  />
85
96
  {/if}
@@ -1,19 +1,6 @@
1
1
  import type { FileData } from "@gradio/client";
2
2
  import type { I18nFormatter } from "@gradio/utils";
3
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
4
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
5
- $$bindings?: Bindings;
6
- } & Exports;
7
- (internal: unknown, props: Props & {
8
- $$events?: Events;
9
- $$slots?: Slots;
10
- }): Exports & {
11
- $set?: any;
12
- $on?: any;
13
- };
14
- z_$$bindings?: Bindings;
15
- }
16
- declare const Model3D: $$__sveltets_2_IsomorphicComponent<{
3
+ type $$ComponentProps = {
17
4
  value: FileData | null;
18
5
  display_mode?: "solid" | "point_cloud" | "wireframe";
19
6
  clear_color?: [number, number, number, number];
@@ -24,8 +11,7 @@ declare const Model3D: $$__sveltets_2_IsomorphicComponent<{
24
11
  pan_speed?: number;
25
12
  camera_position?: [number | null, number | null, number | null];
26
13
  has_change_history?: boolean;
27
- }, {
28
- [evt: string]: CustomEvent<any>;
29
- }, {}, {}, string>;
30
- type Model3D = InstanceType<typeof Model3D>;
14
+ };
15
+ declare const Model3D: import("svelte").Component<$$ComponentProps, {}, "">;
16
+ type Model3D = ReturnType<typeof Model3D>;
31
17
  export default Model3D;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher, tick } from "svelte";
2
+ import { tick } from "svelte";
3
3
  import { Upload, ModifyUpload } from "@gradio/upload";
4
4
  import type { FileData, Client } from "@gradio/client";
5
5
  import { BlockLabel } from "@gradio/atoms";
@@ -8,47 +8,56 @@
8
8
  import type Canvas3DGS from "./Canvas3DGS.svelte";
9
9
  import type Canvas3D from "./Canvas3D.svelte";
10
10
 
11
- export let value: null | FileData;
12
- export let display_mode: "solid" | "point_cloud" | "wireframe" = "solid";
13
- export let clear_color: [number, number, number, number] = [0, 0, 0, 0];
14
- export let label = "";
15
- export let show_label: boolean;
16
- export let root: string;
17
- export let i18n: I18nFormatter;
18
- export let zoom_speed = 1;
19
- export let pan_speed = 1;
20
- export let max_file_size: number | null = null;
21
- export let uploading = false;
22
- export let upload_promise: Promise<(FileData | null)[]> | null = null;
11
+ let {
12
+ value = $bindable(),
13
+ display_mode = "solid",
14
+ clear_color = [0, 0, 0, 0],
15
+ label = "",
16
+ show_label,
17
+ root,
18
+ i18n,
19
+ zoom_speed = 1,
20
+ pan_speed = 1,
21
+ max_file_size = null,
22
+ uploading = $bindable(),
23
+ upload_promise = $bindable(),
24
+ camera_position = [null, null, null],
25
+ upload,
26
+ stream_handler,
27
+ onchange,
28
+ onclear,
29
+ ondrag,
30
+ onload,
31
+ onerror
32
+ }: {
33
+ value?: FileData | null;
34
+ display_mode?: "solid" | "point_cloud" | "wireframe";
35
+ clear_color?: [number, number, number, number];
36
+ label?: string;
37
+ show_label: boolean;
38
+ root: string;
39
+ i18n: I18nFormatter;
40
+ zoom_speed?: number;
41
+ pan_speed?: number;
42
+ max_file_size?: number | null;
43
+ uploading?: boolean;
44
+ upload_promise?: Promise<(FileData | null)[]> | null;
45
+ camera_position?: [number | null, number | null, number | null];
46
+ upload: Client["upload"];
47
+ stream_handler: Client["stream"];
48
+ onchange?: (value: FileData | null) => void;
49
+ onclear?: () => void;
50
+ ondrag?: (dragging: boolean) => void;
51
+ onload?: (value: FileData) => void;
52
+ onerror?: (error: string) => void;
53
+ } = $props();
23
54
 
24
- // alpha, beta, radius
25
- export let camera_position: [number | null, number | null, number | null] = [
26
- null,
27
- null,
28
- null
29
- ];
30
- export let upload: Client["upload"];
31
- export let stream_handler: Client["stream"];
55
+ let use_3dgs = $state(false);
56
+ let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
57
+ let Canvas3DComponent = $state<typeof Canvas3D>();
58
+ let canvas3d = $state<Canvas3D | undefined>();
59
+ let dragging = $state(false);
32
60
 
33
- async function handle_upload({
34
- detail
35
- }: CustomEvent<FileData>): Promise<void> {
36
- value = detail;
37
- await tick();
38
- dispatch("change", value);
39
- dispatch("load", value);
40
- }
41
-
42
- async function handle_clear(): Promise<void> {
43
- value = null;
44
- await tick();
45
- dispatch("clear");
46
- dispatch("change");
47
- }
48
-
49
- let use_3dgs = false;
50
- let Canvas3DGSComponent: typeof Canvas3DGS;
51
- let Canvas3DComponent: typeof Canvas3D;
52
61
  async function loadCanvas3D(): Promise<typeof Canvas3D> {
53
62
  const module = await import("./Canvas3D.svelte");
54
63
  return module.default;
@@ -57,34 +66,47 @@
57
66
  const module = await import("./Canvas3DGS.svelte");
58
67
  return module.default;
59
68
  }
60
- $: if (value) {
61
- use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
62
- if (use_3dgs) {
63
- loadCanvas3DGS().then((component) => {
64
- Canvas3DGSComponent = component;
65
- });
66
- } else {
67
- loadCanvas3D().then((component) => {
68
- Canvas3DComponent = component;
69
- });
69
+
70
+ $effect(() => {
71
+ if (value) {
72
+ use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
73
+ if (use_3dgs) {
74
+ loadCanvas3DGS().then((component) => {
75
+ Canvas3DGSComponent = component;
76
+ });
77
+ } else {
78
+ loadCanvas3D().then((component) => {
79
+ Canvas3DComponent = component;
80
+ });
81
+ }
70
82
  }
83
+ });
84
+
85
+ $effect(() => {
86
+ ondrag?.(dragging);
87
+ });
88
+
89
+ async function handle_upload(detail: FileData): Promise<void> {
90
+ value = detail;
91
+ await tick();
92
+ onchange?.(value);
93
+ onload?.(value as FileData);
94
+ }
95
+
96
+ async function handle_clear(): Promise<void> {
97
+ value = null;
98
+ await tick();
99
+ onclear?.();
100
+ onchange?.(null);
71
101
  }
72
102
 
73
- let canvas3d: Canvas3D | undefined;
74
103
  async function handle_undo(): Promise<void> {
75
104
  canvas3d?.reset_camera_position();
76
105
  }
77
106
 
78
- const dispatch = createEventDispatcher<{
79
- change: FileData | null;
80
- clear: undefined;
81
- drag: boolean;
82
- load: FileData;
83
- }>();
84
-
85
- let dragging = false;
86
-
87
- $: dispatch("drag", dragging);
107
+ function handle_error(error: string): void {
108
+ onerror?.(error);
109
+ }
88
110
  </script>
89
111
 
90
112
  <BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
@@ -94,13 +116,13 @@
94
116
  bind:upload_promise
95
117
  {upload}
96
118
  {stream_handler}
97
- on:load={handle_upload}
119
+ onload={handle_upload}
98
120
  {root}
99
121
  {max_file_size}
100
122
  filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
101
123
  bind:dragging
102
124
  bind:uploading
103
- on:error
125
+ onerror={handle_error}
104
126
  aria_label={i18n("model3d.drop_to_upload")}
105
127
  >
106
128
  <slot />
@@ -109,9 +131,9 @@
109
131
  <div class="input-model">
110
132
  <ModifyUpload
111
133
  undoable={!use_3dgs}
112
- on:clear={handle_clear}
134
+ onclear={handle_clear}
113
135
  {i18n}
114
- on:undo={handle_undo}
136
+ onundo={handle_undo}
115
137
  />
116
138
 
117
139
  {#if use_3dgs}
@@ -1,5 +1,27 @@
1
1
  import type { FileData, Client } from "@gradio/client";
2
2
  import type { I18nFormatter } from "@gradio/utils";
3
+ type $$ComponentProps = {
4
+ value?: FileData | null;
5
+ display_mode?: "solid" | "point_cloud" | "wireframe";
6
+ clear_color?: [number, number, number, number];
7
+ label?: string;
8
+ show_label: boolean;
9
+ root: string;
10
+ i18n: I18nFormatter;
11
+ zoom_speed?: number;
12
+ pan_speed?: number;
13
+ max_file_size?: number | null;
14
+ uploading?: boolean;
15
+ upload_promise?: Promise<(FileData | null)[]> | null;
16
+ camera_position?: [number | null, number | null, number | null];
17
+ upload: Client["upload"];
18
+ stream_handler: Client["stream"];
19
+ onchange?: (value: FileData | null) => void;
20
+ onclear?: () => void;
21
+ ondrag?: (dragging: boolean) => void;
22
+ onload?: (value: FileData) => void;
23
+ onerror?: (error: string) => void;
24
+ };
3
25
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
4
26
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
5
27
  $$bindings?: Bindings;
@@ -18,34 +40,12 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
18
40
  } ? Props extends Record<string, never> ? any : {
19
41
  children?: any;
20
42
  } : {});
21
- declare const Model3DUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
22
- value: null | FileData;
23
- display_mode?: "solid" | "point_cloud" | "wireframe";
24
- clear_color?: [number, number, number, number];
25
- label?: string;
26
- show_label: boolean;
27
- root: string;
28
- i18n: I18nFormatter;
29
- zoom_speed?: number;
30
- pan_speed?: number;
31
- max_file_size?: number | null;
32
- uploading?: boolean;
33
- upload_promise?: Promise<(FileData | null)[]> | null;
34
- camera_position?: [number | null, number | null, number | null];
35
- upload: Client["upload"];
36
- stream_handler: Client["stream"];
37
- }, {
43
+ declare const Model3DUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<$$ComponentProps, {
38
44
  default: {};
39
45
  }>, {
40
- error: CustomEvent<any>;
41
- change: CustomEvent<FileData | null>;
42
- clear: CustomEvent<undefined>;
43
- drag: CustomEvent<boolean>;
44
- load: CustomEvent<FileData>;
45
- } & {
46
46
  [evt: string]: CustomEvent<any>;
47
47
  }, {
48
48
  default: {};
49
- }, {}, string>;
49
+ }, {}, "value" | "uploading" | "upload_promise">;
50
50
  type Model3DUpload = InstanceType<typeof Model3DUpload>;
51
51
  export default Model3DUpload;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/model3d",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -13,15 +13,15 @@
13
13
  "@types/babylon": "^6.16.9",
14
14
  "dequal": "^2.0.3",
15
15
  "gsplat": "^1.2.9",
16
- "@gradio/atoms": "^0.20.0",
17
- "@gradio/icons": "^0.15.0",
18
- "@gradio/statustracker": "^0.12.1",
19
- "@gradio/upload": "^0.17.3",
20
- "@gradio/client": "^2.0.1",
21
- "@gradio/utils": "^0.11.0"
16
+ "@gradio/atoms": "^0.20.1",
17
+ "@gradio/client": "^2.0.3",
18
+ "@gradio/upload": "^0.17.4",
19
+ "@gradio/icons": "^0.15.1",
20
+ "@gradio/utils": "^0.11.2",
21
+ "@gradio/statustracker": "^0.12.2"
22
22
  },
23
23
  "devDependencies": {
24
- "@gradio/preview": "^0.15.1"
24
+ "@gradio/preview": "^0.15.2"
25
25
  },
26
26
  "main_changeset": true,
27
27
  "main": "./Index.svelte",
@@ -44,7 +44,7 @@
44
44
  "./package.json": "./package.json"
45
45
  },
46
46
  "peerDependencies": {
47
- "svelte": "^5.43.4"
47
+ "svelte": "^5.48.0"
48
48
  },
49
49
  "repository": {
50
50
  "type": "git",
@@ -5,19 +5,28 @@
5
5
 
6
6
  let BABYLON_VIEWER: typeof import("@babylonjs/viewer");
7
7
 
8
- export let value: FileData;
9
- export let display_mode: "solid" | "point_cloud" | "wireframe";
10
- export let clear_color: [number, number, number, number];
11
- export let camera_position: [number | null, number | null, number | null];
12
- export let zoom_speed: number;
13
- export let pan_speed: number;
8
+ let {
9
+ value,
10
+ display_mode,
11
+ clear_color,
12
+ camera_position,
13
+ zoom_speed,
14
+ pan_speed
15
+ }: {
16
+ value: FileData;
17
+ display_mode: "solid" | "point_cloud" | "wireframe";
18
+ clear_color: [number, number, number, number];
19
+ camera_position: [number | null, number | null, number | null];
20
+ zoom_speed: number;
21
+ pan_speed: number;
22
+ } = $props();
14
23
 
15
- $: url = value.url;
24
+ let url = $derived(value.url);
16
25
 
17
26
  let canvas: HTMLCanvasElement;
18
- let viewer: Viewer;
19
- let viewerDetails: Readonly<ViewerDetails>;
20
- let mounted = false;
27
+ let viewer = $state<Viewer>();
28
+ let viewerDetails = $state<Readonly<ViewerDetails>>();
29
+ let mounted = $state(false);
21
30
 
22
31
  onMount(() => {
23
32
  const initViewer = async (): Promise<void> => {
@@ -43,9 +52,14 @@
43
52
  };
44
53
  });
45
54
 
46
- $: mounted && load_model(url);
55
+ $effect(() => {
56
+ if (mounted) {
57
+ load_model(url);
58
+ }
59
+ });
47
60
 
48
61
  function setRenderingMode(pointsCloud: boolean, wireframe: boolean): void {
62
+ if (!viewerDetails) return;
49
63
  viewerDetails.scene.forcePointsCloud = pointsCloud;
50
64
  viewerDetails.scene.forceWireframe = wireframe;
51
65
  }
@@ -81,6 +95,7 @@
81
95
  zoom_speed: number,
82
96
  pan_speed: number
83
97
  ): void {
98
+ if (!viewerDetails) return;
84
99
  const camera = viewerDetails.camera;
85
100
  if (camera_position[0] !== null) {
86
101
  camera.alpha = (camera_position[0] * Math.PI) / 180;
@@ -101,7 +116,7 @@
101
116
  }
102
117
 
103
118
  export function reset_camera_position(): void {
104
- if (viewerDetails) {
119
+ if (viewerDetails && viewer) {
105
120
  viewer.resetCamera();
106
121
  }
107
122
  }
@@ -3,19 +3,25 @@
3
3
  import * as SPLAT from "gsplat";
4
4
  import type { FileData } from "@gradio/client";
5
5
 
6
- export let value: FileData;
7
- export let zoom_speed: number;
8
- export let pan_speed: number;
9
-
10
- $: url = value.url;
6
+ let {
7
+ value,
8
+ zoom_speed,
9
+ pan_speed
10
+ }: {
11
+ value: FileData;
12
+ zoom_speed: number;
13
+ pan_speed: number;
14
+ } = $props();
15
+
16
+ let url = $derived(value.url);
11
17
 
12
18
  let canvas: HTMLCanvasElement;
13
19
  let scene: SPLAT.Scene;
14
20
  let camera: SPLAT.Camera;
15
- let renderer: SPLAT.WebGLRenderer | null = null;
21
+ let renderer = $state<SPLAT.WebGLRenderer | null>(null);
16
22
  let controls: SPLAT.OrbitControls;
17
- let mounted = false;
18
- let frameId: number | null = null;
23
+ let mounted = $state(false);
24
+ let frameId = $state<number | null>(null);
19
25
 
20
26
  function reset_scene(): void {
21
27
  if (frameId !== null) {
@@ -92,11 +98,13 @@
92
98
  };
93
99
  });
94
100
 
95
- $: ({ path } = value || {
96
- path: undefined
97
- });
101
+ let path = $derived(value?.path);
98
102
 
99
- $: canvas && mounted && path && reset_scene();
103
+ $effect(() => {
104
+ if (canvas && mounted && path) {
105
+ reset_scene();
106
+ }
107
+ });
100
108
  </script>
101
109
 
102
110
  <canvas bind:this={canvas}></canvas>
@@ -7,27 +7,36 @@
7
7
  import type Canvas3DGS from "./Canvas3DGS.svelte";
8
8
  import type Canvas3D from "./Canvas3D.svelte";
9
9
 
10
- export let value: FileData | null;
11
- export let display_mode: "solid" | "point_cloud" | "wireframe" = "solid";
12
- export let clear_color: [number, number, number, number] = [0, 0, 0, 0];
13
- export let label = "";
14
- export let show_label: boolean;
15
- export let i18n: I18nFormatter;
16
- export let zoom_speed = 1;
17
- export let pan_speed = 1;
18
- // alpha, beta, radius
19
- export let camera_position: [number | null, number | null, number | null] = [
20
- null,
21
- null,
22
- null
23
- ];
24
- export let has_change_history = false;
10
+ let {
11
+ value,
12
+ display_mode = "solid",
13
+ clear_color = [0, 0, 0, 0],
14
+ label = "",
15
+ show_label,
16
+ i18n,
17
+ zoom_speed = 1,
18
+ pan_speed = 1,
19
+ camera_position = [null, null, null],
20
+ has_change_history = false
21
+ }: {
22
+ value: FileData | null;
23
+ display_mode?: "solid" | "point_cloud" | "wireframe";
24
+ clear_color?: [number, number, number, number];
25
+ label?: string;
26
+ show_label: boolean;
27
+ i18n: I18nFormatter;
28
+ zoom_speed?: number;
29
+ pan_speed?: number;
30
+ camera_position?: [number | null, number | null, number | null];
31
+ has_change_history?: boolean;
32
+ } = $props();
25
33
 
26
- let current_settings = { camera_position, zoom_speed, pan_speed };
34
+ let current_settings = $state({ camera_position, zoom_speed, pan_speed });
35
+ let use_3dgs = $state(false);
36
+ let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
37
+ let Canvas3DComponent = $state<typeof Canvas3D>();
38
+ let canvas3d = $state<Canvas3D | undefined>();
27
39
 
28
- let use_3dgs = false;
29
- let Canvas3DGSComponent: typeof Canvas3DGS;
30
- let Canvas3DComponent: typeof Canvas3D;
31
40
  async function loadCanvas3D(): Promise<typeof Canvas3D> {
32
41
  const module = await import("./Canvas3D.svelte");
33
42
  return module.default;
@@ -36,25 +45,27 @@
36
45
  const module = await import("./Canvas3DGS.svelte");
37
46
  return module.default;
38
47
  }
39
- $: if (value) {
40
- use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
41
- if (use_3dgs) {
42
- loadCanvas3DGS().then((component) => {
43
- Canvas3DGSComponent = component;
44
- });
45
- } else {
46
- loadCanvas3D().then((component) => {
47
- Canvas3DComponent = component;
48
- });
48
+
49
+ $effect(() => {
50
+ if (value) {
51
+ use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
52
+ if (use_3dgs) {
53
+ loadCanvas3DGS().then((component) => {
54
+ Canvas3DGSComponent = component;
55
+ });
56
+ } else {
57
+ loadCanvas3D().then((component) => {
58
+ Canvas3DComponent = component;
59
+ });
60
+ }
49
61
  }
50
- }
62
+ });
51
63
 
52
- let canvas3d: Canvas3D | undefined;
53
64
  function handle_undo(): void {
54
65
  canvas3d?.reset_camera_position();
55
66
  }
56
67
 
57
- $: {
68
+ $effect(() => {
58
69
  if (
59
70
  !dequal(current_settings.camera_position, camera_position) ||
60
71
  current_settings.zoom_speed !== zoom_speed ||
@@ -63,7 +74,7 @@
63
74
  canvas3d?.update_camera(camera_position, zoom_speed, pan_speed);
64
75
  current_settings = { camera_position, zoom_speed, pan_speed };
65
76
  }
66
- }
77
+ });
67
78
  </script>
68
79
 
69
80
  <BlockLabel
@@ -79,7 +90,7 @@
79
90
  <IconButton
80
91
  Icon={Undo}
81
92
  label="Undo"
82
- on:click={() => handle_undo()}
93
+ onclick={() => handle_undo()}
83
94
  disabled={!has_change_history}
84
95
  />
85
96
  {/if}
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher, tick } from "svelte";
2
+ import { tick } from "svelte";
3
3
  import { Upload, ModifyUpload } from "@gradio/upload";
4
4
  import type { FileData, Client } from "@gradio/client";
5
5
  import { BlockLabel } from "@gradio/atoms";
@@ -8,47 +8,56 @@
8
8
  import type Canvas3DGS from "./Canvas3DGS.svelte";
9
9
  import type Canvas3D from "./Canvas3D.svelte";
10
10
 
11
- export let value: null | FileData;
12
- export let display_mode: "solid" | "point_cloud" | "wireframe" = "solid";
13
- export let clear_color: [number, number, number, number] = [0, 0, 0, 0];
14
- export let label = "";
15
- export let show_label: boolean;
16
- export let root: string;
17
- export let i18n: I18nFormatter;
18
- export let zoom_speed = 1;
19
- export let pan_speed = 1;
20
- export let max_file_size: number | null = null;
21
- export let uploading = false;
22
- export let upload_promise: Promise<(FileData | null)[]> | null = null;
11
+ let {
12
+ value = $bindable(),
13
+ display_mode = "solid",
14
+ clear_color = [0, 0, 0, 0],
15
+ label = "",
16
+ show_label,
17
+ root,
18
+ i18n,
19
+ zoom_speed = 1,
20
+ pan_speed = 1,
21
+ max_file_size = null,
22
+ uploading = $bindable(),
23
+ upload_promise = $bindable(),
24
+ camera_position = [null, null, null],
25
+ upload,
26
+ stream_handler,
27
+ onchange,
28
+ onclear,
29
+ ondrag,
30
+ onload,
31
+ onerror
32
+ }: {
33
+ value?: FileData | null;
34
+ display_mode?: "solid" | "point_cloud" | "wireframe";
35
+ clear_color?: [number, number, number, number];
36
+ label?: string;
37
+ show_label: boolean;
38
+ root: string;
39
+ i18n: I18nFormatter;
40
+ zoom_speed?: number;
41
+ pan_speed?: number;
42
+ max_file_size?: number | null;
43
+ uploading?: boolean;
44
+ upload_promise?: Promise<(FileData | null)[]> | null;
45
+ camera_position?: [number | null, number | null, number | null];
46
+ upload: Client["upload"];
47
+ stream_handler: Client["stream"];
48
+ onchange?: (value: FileData | null) => void;
49
+ onclear?: () => void;
50
+ ondrag?: (dragging: boolean) => void;
51
+ onload?: (value: FileData) => void;
52
+ onerror?: (error: string) => void;
53
+ } = $props();
23
54
 
24
- // alpha, beta, radius
25
- export let camera_position: [number | null, number | null, number | null] = [
26
- null,
27
- null,
28
- null
29
- ];
30
- export let upload: Client["upload"];
31
- export let stream_handler: Client["stream"];
55
+ let use_3dgs = $state(false);
56
+ let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
57
+ let Canvas3DComponent = $state<typeof Canvas3D>();
58
+ let canvas3d = $state<Canvas3D | undefined>();
59
+ let dragging = $state(false);
32
60
 
33
- async function handle_upload({
34
- detail
35
- }: CustomEvent<FileData>): Promise<void> {
36
- value = detail;
37
- await tick();
38
- dispatch("change", value);
39
- dispatch("load", value);
40
- }
41
-
42
- async function handle_clear(): Promise<void> {
43
- value = null;
44
- await tick();
45
- dispatch("clear");
46
- dispatch("change");
47
- }
48
-
49
- let use_3dgs = false;
50
- let Canvas3DGSComponent: typeof Canvas3DGS;
51
- let Canvas3DComponent: typeof Canvas3D;
52
61
  async function loadCanvas3D(): Promise<typeof Canvas3D> {
53
62
  const module = await import("./Canvas3D.svelte");
54
63
  return module.default;
@@ -57,34 +66,47 @@
57
66
  const module = await import("./Canvas3DGS.svelte");
58
67
  return module.default;
59
68
  }
60
- $: if (value) {
61
- use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
62
- if (use_3dgs) {
63
- loadCanvas3DGS().then((component) => {
64
- Canvas3DGSComponent = component;
65
- });
66
- } else {
67
- loadCanvas3D().then((component) => {
68
- Canvas3DComponent = component;
69
- });
69
+
70
+ $effect(() => {
71
+ if (value) {
72
+ use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
73
+ if (use_3dgs) {
74
+ loadCanvas3DGS().then((component) => {
75
+ Canvas3DGSComponent = component;
76
+ });
77
+ } else {
78
+ loadCanvas3D().then((component) => {
79
+ Canvas3DComponent = component;
80
+ });
81
+ }
70
82
  }
83
+ });
84
+
85
+ $effect(() => {
86
+ ondrag?.(dragging);
87
+ });
88
+
89
+ async function handle_upload(detail: FileData): Promise<void> {
90
+ value = detail;
91
+ await tick();
92
+ onchange?.(value);
93
+ onload?.(value as FileData);
94
+ }
95
+
96
+ async function handle_clear(): Promise<void> {
97
+ value = null;
98
+ await tick();
99
+ onclear?.();
100
+ onchange?.(null);
71
101
  }
72
102
 
73
- let canvas3d: Canvas3D | undefined;
74
103
  async function handle_undo(): Promise<void> {
75
104
  canvas3d?.reset_camera_position();
76
105
  }
77
106
 
78
- const dispatch = createEventDispatcher<{
79
- change: FileData | null;
80
- clear: undefined;
81
- drag: boolean;
82
- load: FileData;
83
- }>();
84
-
85
- let dragging = false;
86
-
87
- $: dispatch("drag", dragging);
107
+ function handle_error(error: string): void {
108
+ onerror?.(error);
109
+ }
88
110
  </script>
89
111
 
90
112
  <BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
@@ -94,13 +116,13 @@
94
116
  bind:upload_promise
95
117
  {upload}
96
118
  {stream_handler}
97
- on:load={handle_upload}
119
+ onload={handle_upload}
98
120
  {root}
99
121
  {max_file_size}
100
122
  filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
101
123
  bind:dragging
102
124
  bind:uploading
103
- on:error
125
+ onerror={handle_error}
104
126
  aria_label={i18n("model3d.drop_to_upload")}
105
127
  >
106
128
  <slot />
@@ -109,9 +131,9 @@
109
131
  <div class="input-model">
110
132
  <ModifyUpload
111
133
  undoable={!use_3dgs}
112
- on:clear={handle_clear}
134
+ onclear={handle_clear}
113
135
  {i18n}
114
- on:undo={handle_undo}
136
+ onundo={handle_undo}
115
137
  />
116
138
 
117
139
  {#if use_3dgs}