Skip to content

Commit 758a4d9

Browse files
authored
Viewer Configurator: Add json output + save/load snippet (#16447)
This change introduces two new configurator features: 1. The ability to save/load the current state (to/from snippet server). See https://forum.babylonjs.com/t/babylon-viewer-v2/54317/65 ![image](https://github.com/user-attachments/assets/bd33db53-3c56-4524-ac07-2be32947b4f8) ![image](https://github.com/user-attachments/assets/116bc8c6-d014-47cd-aa7e-7dd52e0c2dd8) 1. The ability to output to json, which can in turn be passed into any of the Viewer layers as the `ViewerOptions` (making the configurator useful even if you aren't using the html layer). ![image](https://github.com/user-attachments/assets/0a12b30a-36d6-428b-95fe-590f7219dffe) Changes to enable this: - Add format dropdown to choose between html and json (html by default). - Improve camera pose management. - Pass an additional `initialConfiguredState` to `useConfiguration` (comes from the loaded config/options). - Use loaded options and default options in all calls to `useConfiguration`. - Add the ability to save the current configuration (as `ViewerOptions`) to snippet server and encode into the url like other Babylon tools. - Add the ability to load a configuration from snippet server (via url) and use it with `ConfigureCustomViewerElement` to determine the initial state of the Viewer within the Configurator. Also fixed a small bug where environment intensity and rotation were not output if the skybox was disabled.
1 parent 731c432 commit 758a4d9

File tree

5 files changed

+382
-99
lines changed

5 files changed

+382
-99
lines changed

packages/tools/viewer-configurator/src/App.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { FunctionComponent } from "react";
2+
import type { ViewerOptions } from "viewer/viewer";
23
import type { ViewerElement } from "viewer/viewerElement";
34

45
import "./App.scss";
@@ -11,16 +12,21 @@ import { Configurator } from "./components/configurator/configurator";
1112
import { useEventfulState } from "./hooks/observableHooks";
1213

1314
export const App: FunctionComponent = () => {
15+
const [viewerOptions, setViewerOptions] = useState<ViewerOptions>();
1416
const [viewerElement, setViewerElement] = useState<ViewerElement>();
1517
const viewerDetails = useEventfulState(() => viewerElement?.viewerDetails, viewerElement, "viewerready");
1618
const viewer = useMemo(() => viewerDetails?.viewer, [viewerDetails]);
1719

1820
return (
1921
<>
2022
<SplitContainer className="appContainer" direction={SplitDirection.Horizontal}>
21-
<Viewer onViewerCreated={setViewerElement} />
23+
<Viewer onViewerCreated={setViewerElement} onOptionsLoaded={setViewerOptions} />
2224
<Splitter size={8} minSize={300} initialSize={400} maxSize={600} controlledSide={ControlledSize.Second} />
23-
<div>{viewerElement && viewerDetails && viewer && <Configurator viewerElement={viewerElement} viewerDetails={viewerDetails} viewer={viewer} />}</div>
25+
<div>
26+
{viewerOptions && viewerElement && viewerDetails && viewer && (
27+
<Configurator viewerOptions={viewerOptions} viewerElement={viewerElement} viewerDetails={viewerDetails} viewer={viewer} />
28+
)}
29+
</div>
2430
</SplitContainer>
2531
<div className="blocker">Viewer Configurator needs a horizontal resolution of at least 900px</div>
2632
</>

packages/tools/viewer-configurator/src/components/babylonViewer/viewer.tsx

+27-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import "./viewer.scss";
2-
import type { FunctionComponent } from "react";
1+
import type { ViewerOptions } from "viewer/viewer";
32
import type { ViewerElement } from "viewer/viewerElement";
3+
import "./viewer.scss";
4+
import { useEffect, type FunctionComponent } from "react";
5+
import { Logger } from "core/Misc/logger";
6+
import { ConfigureCustomViewerElement } from "viewer/viewerElement";
47
import "viewer";
58

69
interface HTML3DElementAttributes extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
@@ -16,11 +19,30 @@ declare global {
1619
// eslint-disable-next-line @typescript-eslint/naming-convention
1720
interface IntrinsicElements {
1821
// eslint-disable-next-line @typescript-eslint/naming-convention
19-
"babylon-viewer": HTML3DElementAttributes;
22+
"configured-babylon-viewer": HTML3DElementAttributes;
2023
}
2124
}
2225
}
2326

24-
export const Viewer: FunctionComponent<{ onViewerCreated: (viewerElement: ViewerElement) => void }> = (props) => {
25-
return <babylon-viewer class="viewerElement" ref={props.onViewerCreated}></babylon-viewer>;
27+
export const Viewer: FunctionComponent<{ onViewerCreated: (element: ViewerElement) => void; onOptionsLoaded: (options: ViewerOptions) => void }> = (props) => {
28+
useEffect(() => {
29+
(async () => {
30+
let options: ViewerOptions = {};
31+
if (window.location.hash) {
32+
try {
33+
const id = window.location.hash.substring(1).replace("#", "/");
34+
const response = await fetch(`https://snippet.babylonjs.com/${id}`);
35+
options = JSON.parse((await response.json()).jsonPayload);
36+
} catch (error: unknown) {
37+
Logger.Error(`Failed to load snippet from URL: ${error}`);
38+
}
39+
}
40+
41+
ConfigureCustomViewerElement("configured-babylon-viewer", options);
42+
43+
props.onOptionsLoaded(options);
44+
})();
45+
}, []);
46+
47+
return <configured-babylon-viewer class="viewerElement" ref={props.onViewerCreated}></configured-babylon-viewer>;
2648
};

packages/tools/viewer-configurator/src/components/configurator/configurator.scss

+7
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@
194194
}
195195
}
196196

197+
.messageLine {
198+
text-align: center;
199+
font-size: 12px;
200+
font-style: italic;
201+
opacity: 0.6;
202+
}
203+
197204
.textInputLine {
198205
height: 100%;
199206

0 commit comments

Comments
 (0)