From e7d63f1e851ac99d956caea9b3dad672cb258bb7 Mon Sep 17 00:00:00 2001 From: Adnane Belmadiaf Date: Wed, 25 Mar 2026 11:48:07 +0100 Subject: [PATCH] feat(Rendering): report missing view node profile imports fixes #3343 --- Documentation/docs/concepts_profile.md | 47 +++++++++++++++++++ .../scripts/generate-sidebar-config.mjs | 5 +- .../SceneGraph/ViewNodeFactory/index.js | 30 +++++++++++- 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 Documentation/docs/concepts_profile.md diff --git a/Documentation/docs/concepts_profile.md b/Documentation/docs/concepts_profile.md new file mode 100644 index 00000000000..8af6ef40320 --- /dev/null +++ b/Documentation/docs/concepts_profile.md @@ -0,0 +1,47 @@ +--- +title: Rendering Profiles +--- + +# Rendering Profiles + +VTK.js rendering profiles are side-effect imports that register rendering implementations for classes used by the scene graph. They keep applications smaller by letting you import only the rendering backends and mapper support you need. + +## Why profiles exist + +Many VTK.js classes are pure pipeline or data-model classes. They only become renderable after a matching rendering profile registers the view-node overrides required by the active backend such as OpenGL or WebGPU. + +Without the relevant profile import, VTK.js can still construct the data objects, actors, mappers, and pipeline, but rendering may fail when the scene graph asks `ViewNodeFactory` to create a backend-specific implementation for one of those classes. + +## Typical usage + +Import a profile near your application entry point before creating the render window content: + +```js +import '@kitware/vtk.js/Rendering/Profiles/Geometry'; +``` + +If you need broader coverage, import the combined profile: + +```js +import '@kitware/vtk.js/Rendering/Profiles/All'; +``` + +## Common profiles + +- `Geometry`: core polygonal rendering support. +- `Volume`: image and volume rendering support. +- `Glyph`: glyph-specific mapper support. +- `Molecule`: sphere and stick mapper support. +- `LIC`: line integral convolution rendering support. +- `All`: imports all supported profiles. + +## When a profile is missing + +A missing profile often shows up as an error from `Rendering/SceneGraph/ViewNodeFactory` saying that no implementation was found for a class and that a rendering profile is likely missing. + +That warning means one of these is true: + +- A built-in renderable class is being used without importing the profile that registers its rendering implementation. +- A custom renderable class has not been registered with the view-node factory. + +If you are unsure which profile is required, importing `Rendering/Profiles/All` is the easiest way to confirm that the issue is profile-related. After that, you can narrow it back down to the smallest profile set your application needs. diff --git a/Documentation/scripts/generate-sidebar-config.mjs b/Documentation/scripts/generate-sidebar-config.mjs index 2428e4db930..0528f75995b 100644 --- a/Documentation/scripts/generate-sidebar-config.mjs +++ b/Documentation/scripts/generate-sidebar-config.mjs @@ -36,7 +36,10 @@ const docsMenu = [ }, { text: 'Concepts', - items: [{ text: 'Widgets', link: 'concepts_widgets.html' }], + items: [ + { text: 'Widgets', link: 'concepts_widgets.html' }, + { text: 'Profiles', link: 'concepts_profile.html' }, + ], }, { text: 'Miscellaneous', diff --git a/Sources/Rendering/SceneGraph/ViewNodeFactory/index.js b/Sources/Rendering/SceneGraph/ViewNodeFactory/index.js index d36b128a38e..1bfa353a776 100644 --- a/Sources/Rendering/SceneGraph/ViewNodeFactory/index.js +++ b/Sources/Rendering/SceneGraph/ViewNodeFactory/index.js @@ -1,5 +1,28 @@ import macro from 'vtk.js/Sources/macros'; +function listClassHierarchy(dataObject) { + const classNames = []; + let depth = 0; + let className = dataObject.getClassName(depth++); + while (className) { + classNames.push(className); + className = dataObject.getClassName(depth++); + } + return classNames; +} + +function buildMissingImplementationMessage(factoryName, classNames) { + const classList = classNames.join(' → '); + return [ + `No ${factoryName} implementation found for ${classNames[0]}.`, + `Class hierarchy: ${classList}.`, + `A rendering Profile is likely missing for ${classNames[0]}.`, + "Try importing '@kitware/vtk.js/Rendering/Profiles/All' or 'vtk.js/Sources/Rendering/Profiles/All',", + 'or import the specific rendering profile needed by this renderable if known.', + 'See https://kitware.github.io/vtk-js/docs/concepts_profile.html for details.', + ].join('\n'); +} + // ---------------------------------------------------------------------------- // vtkViewNodeFactory methods // ---------------------------------------------------------------------------- @@ -18,8 +41,9 @@ function vtkViewNodeFactory(publicAPI, model) { return null; } + const classNames = listClassHierarchy(dataObject); let cpt = 0; - let className = dataObject.getClassName(cpt++); + let className = classNames[cpt++]; let isObject = false; const keys = Object.keys(model.overrides); while (className && !isObject) { @@ -31,7 +55,9 @@ function vtkViewNodeFactory(publicAPI, model) { } if (!isObject) { - return null; + throw new Error( + buildMissingImplementationMessage(publicAPI.getClassName(), classNames) + ); } const vn = model.overrides[className](); vn.setMyFactory(publicAPI);