Skip to content

Feature/property tree topic#195

Open
ylvaselling wants to merge 53 commits intomasterfrom
feature/property-tree-topic
Open

Feature/property tree topic#195
ylvaselling wants to merge 53 commits intomasterfrom
feature/property-tree-topic

Conversation

@ylvaselling
Copy link
Collaborator

@ylvaselling ylvaselling commented Jan 30, 2026

A bunch of performance optimizations regarding the data passing to and from the UI with the purpose of doing a long-term solve for the UI meltdown.

So for testing, try and make the meltdown happen!

  • Moved the property and propertyOwners to Redux entityAdapters. This is because we were pretty much implementing that anyway, but now we can instead rely on RTK and get some nice selectors generated for us.
    • Batch dispatching (upsertMany) instead of multiple dispatches for updating the store (upsertOne in a loop) has a huge impact on startup performance.
  • Created a visibility state in the local slice to track which scene graph nodes are currently visible. This updates whenever a new property value is set for the fade or enable for that scene graph node.
  • Batching updates from properties with a new PropertyBatcher class. This essentially functions as a throttle, but without the risk of missing values.
  • Throttling updates that are streaming, such as the time and the camera.
  • Topic for properties are now sent as one topic to rule them all, rather than individual topic subscriptions. This means less overhead + we get to have a reliable copy of the property tree in Redux.
    • Removed all property subscriptions
  • Also made a radial sweep icon for the checkboxes when fading because it is ✨ fancy ✨ and also so multiple instances of the UI display the same thing (before they didn't, when you checked a scene graph node icon).
  • Added a new hook for property value, and changed useProperty to that when applicable (possible because we now don't need to subscribe to properties)
  • Also did some refactoring of the property tree helpers and hooks to help distinguish small uri-functions from functions that do more logic

To be used with engine PR

Some future work:

  • There are some places where all properties are extracted from a useAppSelector. This is suboptimal as whenever any property changes, this will trigger a re-render. I started to look into this but this PR is big enough as it is. Also I think it will require a big refactor of the scene tree hooks. To extract all propertyOwners is not as bad, as the propertyOwner state doesn't change that often.
  • We probably could optimize the startup of the topics with more granular control, for example by moving the subscribing of the topics to the connectionMiddleware instead of the middlewares for the topics. Now, all of them fire on onConnection, but we don't have a lot of control over which fire first. This would help to make the UI feel way snappier on startup, probably by first getting the property tree as it basically freezes everything for a bit.

Recommended reading: https://redux-toolkit.js.org/api/createEntityAdapter

Edit:

  • Use batching for the time instead of throttling as we were missing values
    • PropertyBatcher is therefore renamed to Batcher

@ylvaselling ylvaselling marked this pull request as ready for review January 30, 2026 15:45
@ylvaselling
Copy link
Collaborator Author

Fixed the reported issues now - layers + adding and removing scene graph nodes should now work. OpenSpace/OpenSpace#3868 is not going to be fixed with this PR as it is related to an issue with the usePropListeningState hook and not the redux store (did some investigation)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 76 out of 76 changed files in this pull request and generated 14 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +210 to +212
effect: () => {
unsubscribe();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid points :)

Copy link
Collaborator

@WeirdRubberDuck WeirdRubberDuck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some more comments.

I think that the checkbox fading should be brought up during a team meeting just to verify that everyone thinks this change is a good idea, but otherwise, I don't really have many comments

Did some testing and could not find any issues. I will also try a two-node setup locally on my machine and do some testing in the dome

Comment on lines +163 to +165
properties.forEach((p) => {
propertiesMap[p.uri] = p;
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point - it makes sense 👍 would be great if we came to a consensus on a style to use and stick to that everywhere

Comment on lines +26 to +29
const properties = useAppSelector((state) => propertySelectors.selectEntities(state));
const propertyOwners = useAppSelector((state) =>
propertyOwnerSelectors.selectEntities(state)
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the details! 🙏

My general feeling is that having the hooks would be worth it, at least in the places where we get all properties or property owners. It's a lot easier to read a hook that says, for example, allProperties and allPropertyowners instead of these two lines

const properties = useAppSelector((state) => propertySelectors.selectEntities(state));
const propertyOwners = useAppSelector((state) => propertyOwnerSelectors.selectEntities(state));

But this might be biased on how often we had to e.g. get all properties before, and just not being used to the new "entities" concept. So I'm open to discussion and being convinced otherwise

What do you think @engbergandreas ?

if (visibility === 'Fading' && fade !== undefined) {
return (
<ActionIcon size={20}>
<RadialSweepIcon value={fade * 100} background={'transparent'} size={20} />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to discuss it during a meeting? To make sure? Considering that it's a relatively big visual change, and it changes the "instantaneous" feeling of clicking the checkbox, it might be good to get more opinions

The new "fading" checkbox is not as much of a visual change, but I found it a little confusing when enabling/disabling multiple things in sequence. The visual feedback is slightly delayed, which is quite noticeable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants