@gradio/model3d 0.16.0 → 0.16.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,16 @@
1
1
  # @gradio/model3d
2
2
 
3
+ ## 0.16.1
4
+
5
+ ### Fixes
6
+
7
+ - [#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!
8
+
9
+ ### Dependency updates
10
+
11
+ - @gradio/utils@0.11.1
12
+ - @gradio/client@2.0.2
13
+
3
14
  ## 0.16.0
4
15
 
5
16
  ### 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,83 +8,107 @@
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);
60
+
61
+ async function loadCanvas3D(): Promise<typeof Canvas3D> {
62
+ const module = await import("./Canvas3D.svelte");
63
+ return module.default;
64
+ }
65
+ async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
66
+ const module = await import("./Canvas3DGS.svelte");
67
+ return module.default;
68
+ }
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
+ }
82
+ }
83
+ });
84
+
85
+ $effect(() => {
86
+ ondrag?.(dragging);
87
+ });
32
88
 
33
89
  async function handle_upload({
34
90
  detail
35
91
  }: CustomEvent<FileData>): Promise<void> {
36
92
  value = detail;
37
93
  await tick();
38
- dispatch("change", value);
39
- dispatch("load", value);
94
+ onchange?.(value);
95
+ onload?.(value as FileData);
40
96
  }
41
97
 
42
98
  async function handle_clear(): Promise<void> {
43
99
  value = null;
44
100
  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
- async function loadCanvas3D(): Promise<typeof Canvas3D> {
53
- const module = await import("./Canvas3D.svelte");
54
- return module.default;
55
- }
56
- async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
57
- const module = await import("./Canvas3DGS.svelte");
58
- return module.default;
59
- }
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
- });
70
- }
101
+ onclear?.();
102
+ onchange?.(null);
71
103
  }
72
104
 
73
- let canvas3d: Canvas3D | undefined;
74
105
  async function handle_undo(): Promise<void> {
75
106
  canvas3d?.reset_camera_position();
76
107
  }
77
108
 
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);
109
+ function handle_error({ detail }: CustomEvent<string>): void {
110
+ onerror?.(detail);
111
+ }
88
112
  </script>
89
113
 
90
114
  <BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
@@ -100,7 +124,7 @@
100
124
  filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
101
125
  bind:dragging
102
126
  bind:uploading
103
- on:error
127
+ on:error={handle_error}
104
128
  aria_label={i18n("model3d.drop_to_upload")}
105
129
  >
106
130
  <slot />
@@ -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.1",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -14,11 +14,11 @@
14
14
  "dequal": "^2.0.3",
15
15
  "gsplat": "^1.2.9",
16
16
  "@gradio/atoms": "^0.20.0",
17
- "@gradio/icons": "^0.15.0",
17
+ "@gradio/client": "^2.0.2",
18
18
  "@gradio/statustracker": "^0.12.1",
19
+ "@gradio/icons": "^0.15.0",
19
20
  "@gradio/upload": "^0.17.3",
20
- "@gradio/client": "^2.0.1",
21
- "@gradio/utils": "^0.11.0"
21
+ "@gradio/utils": "^0.11.1"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@gradio/preview": "^0.15.1"
@@ -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,83 +8,107 @@
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);
60
+
61
+ async function loadCanvas3D(): Promise<typeof Canvas3D> {
62
+ const module = await import("./Canvas3D.svelte");
63
+ return module.default;
64
+ }
65
+ async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
66
+ const module = await import("./Canvas3DGS.svelte");
67
+ return module.default;
68
+ }
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
+ }
82
+ }
83
+ });
84
+
85
+ $effect(() => {
86
+ ondrag?.(dragging);
87
+ });
32
88
 
33
89
  async function handle_upload({
34
90
  detail
35
91
  }: CustomEvent<FileData>): Promise<void> {
36
92
  value = detail;
37
93
  await tick();
38
- dispatch("change", value);
39
- dispatch("load", value);
94
+ onchange?.(value);
95
+ onload?.(value as FileData);
40
96
  }
41
97
 
42
98
  async function handle_clear(): Promise<void> {
43
99
  value = null;
44
100
  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
- async function loadCanvas3D(): Promise<typeof Canvas3D> {
53
- const module = await import("./Canvas3D.svelte");
54
- return module.default;
55
- }
56
- async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
57
- const module = await import("./Canvas3DGS.svelte");
58
- return module.default;
59
- }
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
- });
70
- }
101
+ onclear?.();
102
+ onchange?.(null);
71
103
  }
72
104
 
73
- let canvas3d: Canvas3D | undefined;
74
105
  async function handle_undo(): Promise<void> {
75
106
  canvas3d?.reset_camera_position();
76
107
  }
77
108
 
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);
109
+ function handle_error({ detail }: CustomEvent<string>): void {
110
+ onerror?.(detail);
111
+ }
88
112
  </script>
89
113
 
90
114
  <BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
@@ -100,7 +124,7 @@
100
124
  filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
101
125
  bind:dragging
102
126
  bind:uploading
103
- on:error
127
+ on:error={handle_error}
104
128
  aria_label={i18n("model3d.drop_to_upload")}
105
129
  >
106
130
  <slot />