Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
604286e
Make MessageBar title/message optional
alexchuber Dec 18, 2025
cf332d7
Update author and leave note
alexchuber Dec 18, 2025
ea859ad
Add GLTF tools (settings, validator) to Import Tools
alexchuber Dec 18, 2025
5f7abe7
Refactor
alexchuber Jan 12, 2026
70004e5
Fix validation results being discarded whenever Inspector is recreated
alexchuber Jan 15, 2026
d937a5e
Nits for validation tool
alexchuber Jan 15, 2026
30e0d55
Move validationResult state to GLTFValidation
alexchuber Jan 15, 2026
8a0a1c6
Lazy initialize results history
alexchuber Jan 15, 2026
5cb4f79
Simplify loader options state mgmt
alexchuber Jan 15, 2026
e6880ea
Naming & comment nits
alexchuber Jan 15, 2026
d56f476
Add "indentExpandedContent" option to ExpandableProperty props
alexchuber Jan 24, 2026
8fc86ac
Missed a spot for indentExpandedContent
alexchuber Jan 24, 2026
12f2d6e
Loop through extensionOptions to create components
alexchuber Jan 24, 2026
05fc2f8
Use child window for glTF validation results
alexchuber Jan 24, 2026
27da23d
Fix MessageBar optional props
alexchuber Jan 24, 2026
ebca3fa
Keep all weird GLTFValidation statics internal
alexchuber Jan 24, 2026
c7f4fee
Simplify lo-fi GLTFValidation solution
alexchuber Jan 26, 2026
36f03d4
Forgot to remove import
alexchuber Jan 26, 2026
a95bcae
Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into…
alexchuber Jan 26, 2026
0523353
Merge remote-tracking branch 'origin/master' into inspector-v2-import…
ryantrem Jan 27, 2026
9fb6e8b
Use ChildWindow
ryantrem Jan 27, 2026
68d853e
Use GLTFLoaderDefaultOptions
ryantrem Jan 27, 2026
6192840
Merge remote-tracking branch 'origin/master' into inspector-v2-import…
ryantrem Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const AnimationGroupLoadingModes = [
{ label: "NoSync", value: SceneLoaderAnimationGroupLoadingMode.NoSync },
] as const satisfies DropdownOption<number>[];

export const ImportAnimationsTools: FunctionComponent<{ scene: Scene }> = ({ scene }) => {
export const GLTFAnimationImportTool: FunctionComponent<{ scene: Scene }> = ({ scene }) => {
const [importDefaults, setImportDefaults] = useState({
overwriteAnimations: true,
animationGroupLoadingMode: SceneLoaderAnimationGroupLoadingMode.Clean,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import type { FunctionComponent } from "react";
import { GLTFLoaderCoordinateSystemMode, GLTFLoaderAnimationStartMode } from "loaders/glTF/glTFFileLoader";
import type { DropdownOption } from "shared-ui-components/fluent/primitives/dropdown";
import { SwitchPropertyLine } from "shared-ui-components/fluent/hoc/propertyLines/switchPropertyLine";
import { NumberDropdownPropertyLine } from "shared-ui-components/fluent/hoc/propertyLines/dropdownPropertyLine";
import { SyncedSliderPropertyLine } from "shared-ui-components/fluent/hoc/propertyLines/syncedSliderPropertyLine";
import type { GLTFExtensionOptionsType, GLTFLoaderOptionsType } from "../../../services/panes/tools/import/gltfLoaderOptionsService";
import { PropertyLine } from "shared-ui-components/fluent/hoc/propertyLines/propertyLine";
import { tokens } from "@fluentui/react-components";
import { BoundProperty } from "../../properties/boundProperty";

const AnimationStartModeOptions: DropdownOption<number>[] = [
{ label: "None", value: GLTFLoaderAnimationStartMode.NONE },
{ label: "First", value: GLTFLoaderAnimationStartMode.FIRST },
{ label: "All", value: GLTFLoaderAnimationStartMode.ALL },
];

const CoordinateSystemModeOptions: DropdownOption<number>[] = [
{ label: "Auto", value: GLTFLoaderCoordinateSystemMode.AUTO },
{ label: "Right Handed", value: GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED },
];

export const GLTFLoaderOptionsTool: FunctionComponent<{
loaderOptions: GLTFLoaderOptionsType;
}> = ({ loaderOptions }) => {
return (
<PropertyLine
label="Loader Options"
expandByDefault={false}
expandedContent={
<div style={{ paddingLeft: tokens.spacingHorizontalM }}>
Comment thread
ryantrem marked this conversation as resolved.
Outdated
<BoundProperty component={SwitchPropertyLine} label="Always compute bounding box" target={loaderOptions} propertyKey="alwaysComputeBoundingBox" />
<BoundProperty component={SwitchPropertyLine} label="Always compute skeleton root node" target={loaderOptions} propertyKey="alwaysComputeSkeletonRootNode" />
<BoundProperty
component={NumberDropdownPropertyLine}
label="Animation start mode"
options={AnimationStartModeOptions}
target={loaderOptions}
propertyKey="animationStartMode"
/>
<BoundProperty component={SwitchPropertyLine} label="Capture performance counters" target={loaderOptions} propertyKey="capturePerformanceCounters" />
<BoundProperty component={SwitchPropertyLine} label="Compile materials" target={loaderOptions} propertyKey="compileMaterials" />
<BoundProperty component={SwitchPropertyLine} label="Compile shadow generators" target={loaderOptions} propertyKey="compileShadowGenerators" />
<BoundProperty
component={NumberDropdownPropertyLine}
label="Coordinate system"
options={CoordinateSystemModeOptions}
target={loaderOptions}
propertyKey="coordinateSystemMode"
/>
<BoundProperty component={SwitchPropertyLine} label="Create instances" target={loaderOptions} propertyKey="createInstances" />
<BoundProperty component={SwitchPropertyLine} label="Enable logging" target={loaderOptions} propertyKey="loggingEnabled" />
<BoundProperty component={SwitchPropertyLine} label="Load all materials" target={loaderOptions} propertyKey="loadAllMaterials" />
<BoundProperty component={SyncedSliderPropertyLine} label="Target FPS" target={loaderOptions} propertyKey="targetFps" min={1} max={120} step={1} />
<BoundProperty component={SwitchPropertyLine} label="Transparency as coverage" target={loaderOptions} propertyKey="transparencyAsCoverage" />
<BoundProperty component={SwitchPropertyLine} label="Use clip plane" target={loaderOptions} propertyKey="useClipPlane" />
<BoundProperty component={SwitchPropertyLine} label="Use sRGB buffers" target={loaderOptions} propertyKey="useSRGBBuffers" />
</div>
}
/>
);
};

export const GLTFExtensionOptionsTool: FunctionComponent<{
extensionOptions: GLTFExtensionOptionsType;
}> = ({ extensionOptions }) => {
return (
<PropertyLine
label="Extension Options"
expandByDefault={false}
expandedContent={
<div style={{ paddingLeft: tokens.spacingHorizontalM }}>
<BoundProperty
Comment thread
alexchuber marked this conversation as resolved.
Outdated
label="EXT_lights_image_based"
component={SwitchPropertyLine}
key="EXT_lights_image_based_enabled"
target={extensionOptions["EXT_lights_image_based"]}
Comment thread
alexchuber marked this conversation as resolved.
Outdated
propertyKey="enabled"
/>
<BoundProperty
label="EXT_mesh_gpu_instancing"
component={SwitchPropertyLine}
key="EXT_mesh_gpu_instancing_enabled"
target={extensionOptions["EXT_mesh_gpu_instancing"]}
propertyKey="enabled"
/>
<BoundProperty component={SwitchPropertyLine} label="EXT_texture_webp" target={extensionOptions["EXT_texture_webp"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="EXT_texture_avif" target={extensionOptions["EXT_texture_avif"]} propertyKey="enabled" />
<BoundProperty
component={SwitchPropertyLine}
label="KHR_draco_mesh_compression"
target={extensionOptions["KHR_draco_mesh_compression"]}
propertyKey="enabled"
/>
<BoundProperty
component={SwitchPropertyLine}
label="KHR_materials_pbrSpecularGlossiness"
target={extensionOptions["KHR_materials_pbrSpecularGlossiness"]}
propertyKey="enabled"
/>
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_clearcoat" target={extensionOptions["KHR_materials_clearcoat"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_iridescence" target={extensionOptions["KHR_materials_iridescence"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_anisotropy" target={extensionOptions["KHR_materials_anisotropy"]} propertyKey="enabled" />
<BoundProperty
component={SwitchPropertyLine}
label="KHR_materials_emissive_strength"
target={extensionOptions["KHR_materials_emissive_strength"]}
propertyKey="enabled"
/>
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_ior" target={extensionOptions["KHR_materials_ior"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_sheen" target={extensionOptions["KHR_materials_sheen"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_specular" target={extensionOptions["KHR_materials_specular"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_unlit" target={extensionOptions["KHR_materials_unlit"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_materials_variants" target={extensionOptions["KHR_materials_variants"]} propertyKey="enabled" />
<BoundProperty
component={SwitchPropertyLine}
key="KHR_materials_transmission"
label="KHR_materials_transmission"
target={extensionOptions["KHR_materials_transmission"]}
propertyKey="enabled"
/>
<BoundProperty
component={SwitchPropertyLine}
label="KHR_materials_diffuse_transmission"
target={extensionOptions["KHR_materials_diffuse_transmission"]}
propertyKey="enabled"
/>
<BoundProperty
component={SwitchPropertyLine}
key="KHR_materials_volume"
label="KHR_materials_volume"
target={extensionOptions["KHR_materials_volume"]}
propertyKey="enabled"
/>
<BoundProperty
component={SwitchPropertyLine}
key="KHR_materials_dispersion"
label="KHR_materials_dispersion"
target={extensionOptions["KHR_materials_dispersion"]}
propertyKey="enabled"
/>
<BoundProperty
component={SwitchPropertyLine}
label="KHR_materials_diffuse_roughness"
target={extensionOptions["KHR_materials_diffuse_roughness"]}
propertyKey="enabled"
/>
<BoundProperty component={SwitchPropertyLine} label="KHR_mesh_quantization" target={extensionOptions["KHR_mesh_quantization"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_lights_punctual" target={extensionOptions["KHR_lights_punctual"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="EXT_lights_area" target={extensionOptions["EXT_lights_area"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_texture_basisu" target={extensionOptions["KHR_texture_basisu"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_texture_transform" target={extensionOptions["KHR_texture_transform"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="KHR_xmp_json_ld" target={extensionOptions["KHR_xmp_json_ld"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="MSFT_lod" target={extensionOptions["MSFT_lod"]} propertyKey="enabled" />
<div style={{ paddingLeft: tokens.spacingHorizontalM }}>
<BoundProperty
component={SyncedSliderPropertyLine}
label="Maximum LODs"
target={extensionOptions["MSFT_lod"]}
propertyKey="maxLODsToLoad"
min={1}
max={10}
step={1}
/>
</div>
<BoundProperty component={SwitchPropertyLine} label="MSFT_minecraftMesh" target={extensionOptions["MSFT_minecraftMesh"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="MSFT_sRGBFactors" target={extensionOptions["MSFT_sRGBFactors"]} propertyKey="enabled" />
<BoundProperty component={SwitchPropertyLine} label="MSFT_audio_emitter" target={extensionOptions["MSFT_audio_emitter"]} propertyKey="enabled" />
</div>
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useCallback } from "react";
import type { FunctionComponent } from "react";
import { ButtonLine } from "shared-ui-components/fluent/hoc/buttonLine";
import { StringifiedPropertyLine } from "shared-ui-components/fluent/hoc/propertyLines/stringifiedPropertyLine";
import { MessageBar } from "shared-ui-components/fluent/primitives/messageBar";
import type { IGLTFValidationResults } from "babylonjs-gltf2interface";

export const GLTFValidationTool: FunctionComponent<{ validationResults: IGLTFValidationResults }> = ({ validationResults }) => {
const openValidationDetails = useCallback(() => {
Comment thread
ryantrem marked this conversation as resolved.
Outdated
const win = window.open("", "_blank");
if (win) {
// TODO: format this better and use generator registry (https://github.com/KhronosGroup/glTF-Generator-Registry)
Comment thread
ryantrem marked this conversation as resolved.
Outdated
win.document.title = `${validationResults.uri} - glTF Validation Results`;
win.document.body.style.backgroundColor = "#322e2eff";
win.document.body.style.color = "#fff";
win.document.body.style.padding = "1rem";
const pre = win.document.createElement("pre");
const code = win.document.createElement("code");
const textNode = win.document.createTextNode(JSON.stringify(validationResults, null, 2));
code.append(textNode);
pre.append(code);
win.document.body.append(pre);
win.focus();
}
}, [validationResults]);

const issues = validationResults.issues;
const hasErrors = issues.numErrors > 0;

return (
<>
<MessageBar intent={hasErrors ? "error" : "success"} message={hasErrors ? "Your file has validation issues" : "Your file is a valid glTF file"} />
<StringifiedPropertyLine key="NumErrors" label="Errors" value={issues.numErrors} />
<StringifiedPropertyLine key="NumWarnings" label="Warnings" value={issues.numWarnings} />
<StringifiedPropertyLine key="NumInfos" label="Infos" value={issues.numInfos} />
<StringifiedPropertyLine key="NumHints" label="Hints" value={issues.numHints} />
<ButtonLine label="View Report Details" onClick={openValidationDetails} />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspecto
description: "Adds new features related to importing Babylon assets.",
keywords: ["import", "tools"],
...BabylonWebResources,
author: { name: "Alex Chuber", forumUserName: "alexchuber" },
getExtensionModuleAsync: async () => await import("../services/panes/tools/importService"),
author: { name: "Babylon.js", forumUserName: "" },
getExtensionModuleAsync: async () => await import("../services/panes/tools/import/importService"),
},
{
name: "Quick Creation Tools (Preview)",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { ServiceDefinition } from "../../../../modularity/serviceDefinition";
import { ToolsServiceIdentity } from "../../toolsService";
import type { IToolsService } from "../../toolsService";
import { GLTFAnimationImportTool } from "../../../../components/tools/import/gltfAnimationImportTool";

export const GLTFAnimationImportServiceDefinition: ServiceDefinition<[], [IToolsService]> = {
friendlyName: "GLTF Animation Import",
consumes: [ToolsServiceIdentity],
factory: (toolsService) => {
const contentRegistration = toolsService.addSectionContent({
key: "AnimationImport",
order: 40,
section: "GLTF Animation Import",
component: ({ context }) => <GLTFAnimationImportTool scene={context} />,
});

return {
dispose: () => {
contentRegistration.dispose();
},
};
},
};
Loading