3.5.0 Change Notes

Table of contents:

Display system

Reality model display customization

You can now customize various aspects of how a reality model is displayed within a Viewport by applying your own RealityModelDisplaySettings to the model. For contextual reality models, use ContextRealityModel.displaySettings; for persistent reality Models, use DisplayStyleSettings.setRealityModelDisplaySettings.

For all types of reality models, you can customize how the model's color is mixed with a color override applied by a FeatureAppearance or a SpatialClassifier. RealityModelDisplaySettings.overrideColorRatio defaults to 0.5, mixing the two colors equally, but you can adjust it to any value between 0.0 (use only the model's color) and 1.0 (use only the override color).

Point clouds provide the following additional customizations:

View padding

Functions like ViewState.lookAtVolume and Viewport.zoomToElements fit a view to a specified volume. They accept a MarginOptions that allows the caller to customize how tightly the view fits to the volume, via MarginPercent. However, the amount by which the volume is enlarged to add extra space can yield surprising results. For example, a MarginPercent that specifies a margin of 25% on each side - {left: .25, right: .25, top: .25, bottom: .25} - actually doubles the width and height of the volume, adding 50% of the original volume's size to each side. Moreover, MarginPercent's constructor clamps the margin values to a minimum of zero and maximum of 0.25.

Now, MarginOptions has an alternative way to specify how to adjust the size of the viewed volume, using MarginOptions.paddingPercent. Like MarginPercent, a PaddingPercent specifies the extra space as a percentage of the original volume's space on each side - though it may also specify a single padding to be applied to all four sides, or omit any side that should have no padding applied. For example,

{paddingPercent: {left: .2, right: .2, top: .2, bottom: .2}}
// is equivalent to
{paddingPercent: .2}


{paddingPercent: {left: 0, top: 0, right: .5, bottom: .5}}
// is equivalent to
{paddingPercent: {right: .5, bottom: .5}

Moreover, PaddingPercent imposes no constraints on the padding values. They can even be negative, which causes the volume to shrink instead of expand by subtracting a percentage of the original volume's size from one or more sides.

The padding computations are more straightforward than those used for margins. For example, {paddingPercent: 0.25} adds 25% of the original volume's size to each side, whereas the equivalent marginPercent adds 50% to each side.

Note that both margins and padding apply only to 2d views, or to 3d views with the camera turned off; and that additional extra space will be allocated on either the top and bottom or left and right to preserve the viewport's aspect ratio.


Controlling in-memory cache sizes

The presentation library uses a number of SQLite connections, each of which have an associated in-memory page cache. Ability to control the size of these caches on the backend has been added to allow consumers fine-tune their configuration based on their memory restrictions and use cases.

The configuration is done when initializing Presentation or creating a PresentationManager:

  caching: {
    // use 8 megabytes page cache for worker connections to iModels
    workerConnectionCacheSize: 8 * 1024 * 1024,
    // use a disk-based hierarchy cache with a 4 megabytes in-memory page cache
    hierarchies: {
      mode: HierarchyCacheMode.Disk,
      memoryCacheSize: 4 * 1024 * 1024,

See the Caching documentation page for more details on various caches used by presentation system.

Changes to infinite hierarchy prevention

The idea of infinite hierarchy prevention is to stop producing hierarchy when we notice duplicate ancestor nodes. See more details about that in the Infinite hierarchy prevention page.

Previously, when a duplicate node was detected, our approach to handle the situation was to just hide the duplicate node altogether. However, in some situations that turned out to be causing mismatches between what we get through a nodes count request and what we get through a nodes request (e.g. the count request returns 2, but the nodes request returns only 1 node). There was no way to keep the count request efficient with this approach of handling infinite hierarchies.

The new approach, instead of hiding the duplicate node, shows it, but without any children. This still "breaks" the hierarchy when we want that, but keeps the count and nodes in sync.


Say, we have two instances A and B and they point to each other through a relationship:

A -> refers to -> B
B -> refers to -> A

With presentation rules we can set up a hierarchy where root node is A, its child is B, whose child is again A, and so on.

With previous approach the produced hierarchy "breaks" at the B node and looks like this:

+ A
+--+ B

With the new approach we "break" at the duplicate A node:

+ A
+--+ B
   +--+ A

Element aspects

Aspect Ids

IModelDb.Elements.insertAspect now returns the id of the newly inserted aspect. Aspects exist in a different id space from elements, so the ids returned are not unique from all element ids and may collide.

ExternalSourceAspect find methods

ExternalSourceAspect.findBySource is deprecated. Use ExternalSourceAspect.findAllBySource instead.

An Element can have more than one ExternalSourceAspect with the same scope, kind, and identifier. Also, many elements could have ExternalSourceAspects with the same scope, kind, and identifier. Therefore, ExternalSourceAspect.findAllBySource returns an array.

If an app expects there to be only one ExternalSourceAspect with a given scope, kind, and identifier in the iModel, it must check that the array returned by ExternalSourceAspect.findAllBySource contains only one item.

To narrow the search to just the ExternalSourceAspects on a single element, use an ECSql query, such as select ecinstanceid from Bis.ExternalSourceAspect where scope.id=? and kind=? and identifier=? and element.id=?. If only one such aspect is expected, verify that only one row is found.


Setting allowed panel zones for widgets

When defining a Widget with AbstractWidgetProperties, you can now specify on which sides of the ContentArea the it can be docked. The optional prop allowedPanelTargets is an array of any of the following: "left", "right", "top", "bottom". By default, all regions are allowed. You must specify at least one allowed target in the array.

New packages


A new @itwin/map-layers-formats package has been introduced to provide additional MapLayerFormats not delivered as part of @itwin/core-frontend. The initial release contains the new ArgGISFeature format which allows vector data published by ArcGIS Feature services to be displayed in a Viewport.

To use this package, you must initialize it by calling MapLayersFormats.initialize to register the additional formats. This should be done only after IModelApp.startup has been called.



The method Polyface.facetCount has been added to this abstract class, with a default implementation that returns undefined. Implementers should override to return the number of facets of the mesh.


The methods CurveCollection.projectedParameterRange and CurvePrimitive.projectedParameterRange have been added for computing the range of fractional projection parameters of the instance curve(s) onto a Ray3d. The default implementation of the latter method returns undefined to avoid a circular dependency, so extenders of CurvePrimitive should override as appropriate.



All non-internal components are deprecated with their corresponding replacements available in @itwin/appui-react package. Going forward @itwin/appui-layout-react package is considered as internal implementation detail of the @itwin/appui-react package and should not be used directly.

Deprecated Replacement
Dialog StatusBarDialog
FooterIndicator StatusBarIndicator
FooterPopup popup prop of StatusBarIndicator
FooterSeparator StatusBarSeparator
SafeAreaInsets SafeAreaInsets
TitleBar StatusBarDialog.TitleBar


A number of UI1.0 related APIs and components are deprecated and will be removed in the next @itwin/appui-react major version: FrameworkVersion, FrameworkVersionContext, FrameworkVersionId, FrameworkVersionProps, ListPickerBase, useFrameworkVersion, NineZoneChangeHandler, StagePanelChangeHandler, WidgetStateFunc, ZoneDefProvider, Zone, ZoneDef.

Pseudo components used by the FrontstageProvider are deprecated and replaced by corresponding configuration interfaces:

Component Replacement
Frontstage FrontstageConfig
Widget WidgetConfig
StagePanel StagePanelConfig

Other deprecations and their replacements:

Deprecated Replacement
ActionItemButton ActionButton
ActivityMessagePopup Activity messages are set-up automatically
Backstage BackstageComposer
BackstageEvent BackstageManager.onToggled
GroupButton GroupButton
Indicator StatusBarIndicator
ToolButton CommonToolbarItem
withSafeArea SafeAreaContext


All the components that were only used by or with the deprecated Table are now marked as deprecated as well and will be removed in an upcoming version. The Table was deprecated a year ago in favor of the Table component provided in the @itwin/itwinui-react package, which do not use any of these parts.


The synchronous IModelDb.Views.getViewStateData has been deprecated in favor of IModelDb.Views.getViewStateProps, which accepts the same inputs and returns the same output, but performs some potentially-expensive work on a background thread to avoid blocking the JavaScript event loop.

The IModelCloneContext class in @itwin/core-backend has been renamed to IModelElementCloneContext to better reflect its inability to clone non-element entities. The type IModelCloneContext is still exported from the package as an alias for IModelElementCloneContext. @itwin/core-transformer now provides a specialization of IModelElementCloneContext named IModelCloneContext.


ByteStream's next property getters like ByteStream.nextUint32 and ByteStream.nextFloat64 have been deprecated and replaced with corresponding read methods like ByteStream.readUint32 and ByteStream.readFloat64. The property getters have the side effect of incrementing the stream's current read position, which can result in surprising behavior and may trip up code optimizers that assume property access is free of side effects.


Localization.getLocalizedStringWithNamespace is deprecated in favor of using Localization.getLocalizedString and providing either a key with a namespace <namespace>:<key> or including { ns: <namespace> } in the options.


The method PathFragment.childFractionTChainDistance has been deprecated in favor of the correctly spelled method PathFragment.childFractionToChainDistance.


IModelTransformer.initFromExternalSourceAspects is deprecated and in most cases no longer needed, because the transformer now handles referencing properties on out-of-order non-element entities like aspects, models, and relationships. If you are not using a method like processAll or processChanges to run the transformer, then you do need to replace initFromExternalSourceAspects with IModelTransformer.initialize.


PresentationManagerProps.mode has been deprecated because there is no performance difference between PresentationManager working in ReadOnly or ReadWrite modes.

Last Updated: 03 February, 2023