Refactor 3D scenes to a modular object system#6085
Conversation
|
I'm still doing work on this PR, but raised it here to get feedback early before I make the final touches. |
|
@HosseyNJF can you explain why 0de5653 Because:
|
|
@evnchn Yeah my bad, I'll create a separate PR for that. About the issue, there is a bug that if a screen test fails, the action won't upload the screenshot of selenium. Btw workflows are enabled on my fork, maybe it's a security toggle that just doesn't let first-time contributors run the actions on a PR? |
bbcd474 to
32354a7
Compare
|
@HosseyNJF You sure enabled? 0 workflow runs at https://github.com/HosseyNJF/nicegui/actions tho |
|
Oops I was looking at the wrong toggle :) I just enabled it now, let me try a push |
32354a7 to
f2f63d5
Compare
|
Well still no. I pressed approve for you on this one.
Some GitHub cost-cutting shenanigans (worth a read if confused)So on my end, I can say is, sometime this year, GitHub definitely did change how the workflow runs are triggered, because it used to be "run on all branches" but some time they changed to "run only on opened PRs", hence why I am forced to track all my branches with PRs at https://github.com/evnchn/niceguiMaybe due to that shenanigan, that this PR is not in the list of branches to monitor because of that mechanism. I think the course of action is to:
|
|
I don't know if I'm doing anything wrong, but I created the PR in my own fork and over there, the workflows are running. But not here for some reason. |
|
Well opening fork PR used to get the trick done. I just don't know how much GitHub wants to cost-cut its workflow runs by ruling more stuff out tho. Then the only thing left to try is to bring 0de5653 out to its own PR. If that doesn't get actions to show up working maybe time for look for pre-existing issues and file it to them, no choice. |
|
Questions for reviewers:
|
|
Hello @evnchn , would you mind assigning the "review" label to this PR, or is there something else I need to do before it's considered ready? |
|
We are slight busy and may not able to handle big feat PRs in 3.13, sorry :( Off the top of my head, I wonder really if there are no breaking changes with this PR. Because If there is breaking change, then we need to discuss if it is worth it, and if it is then we can ship it in 4.0 If there is none, we'll choose a milestone when we are comfortable with handling it and do it. |
|
I totally understand, I just didn't want it to get lost to time :) There are absolutely no breaking changes, since all objects were exported from |
|
Huh interesting. So maybe this statement, when attested to be true, would help the review of the PR which, on paper, has 49 changed files, and
I'll send my agents on this. @HosseyNJF lmk if you think it's true on your side. |
|
That is true, but I'd add this too (since it's an important aspect):
|
|
Reviewed via Claude Code (Claude Opus 4.8) on Evan's behalf — MREs run locally headless against your branch Hey @HosseyNJF — short version: the refactor's solid and you're right it's mostly relocation (the 17 Why we'd still call items 2 & 3 "breaking" (we may just define it differently)Your bar for "absolutely no breaking changes" is the documented Three minimal repros, each run headless against your branch and 1. 🔴 |
main |
this branch | |
|---|---|---|
innerRadius |
0.5 |
"ring" (string) |
| vertex positions | finite | all NaN → nothing renders |
The fix is to drop that leftover 'ring' argument (verified locally — readback goes back to innerRadius=0.5, no NaN). We're a bit swamped right now so I'd rather not push to your branch, but ping me if you'd like the exact one-liner.
2. 🟠 Breaking — runtime .material() silently dropped (create() went async)
create() now returns a Promise (import(name).then(...)). At runtime this documented pattern:
ui.button('add', on_click=lambda: scene.box().material('#ff0000'))sends create then material as separate messages. On the first (uncached) use of an object type, the import hasn't resolved yet, so material() hits if (!object) return; and is lost.
main |
this branch | |
|---|---|---|
| box color after click | #ff0000 (red) |
#ffffff (white — material lost) |
The initial-scene path is safe (init_objects awaits each create); it's specifically runtime-created objects — which is every custom object, i.e. the headline feature. Options: keep built-ins statically imported (sync), or buffer per-object method calls until that object's import resolves.
3. 🟠 Breaking — subclassing Object3D raises at class-definition time
__init_subclass__ now requires component=:
class MyThing(Object3D): # the pattern every built-in used pre-PR
...main |
this branch | |
|---|---|---|
| class definition | OK | TypeError: parameter 'component' must be supplied as a class named argument |
Acceptable if we agree direct Object3D subclassing was never public — but worth stating explicitly, since this PR makes subclassing the official extension path.
The ask: Ring needs fixing. For items 2 & 3 — your call: fix them, or come ready to walk me through why they're intentional and we'll settle on the right approach together. Thanks for the contribution, genuinely nice work on the modular structure 🙏
|
@HosseyNJF So in short: I spot at least 3 to-do items, so maybe this will go in 3.14, at least not 3.13 I guess. 3.13's packed not because of many tickets but because of low human bandwidth so yeah weight's off for this PR then. |
|
Thanks for the review! Yeah that works for me. Off the top of my head, I'd say point 3 is incorrect because the For the rest, I'll take a look and get back to you with fixes. |
|
By the way, please let me know if I can be of any help in other issues/PRs for the 3.13 milestone. |
|
Party's public at https://github.com/zauberzeug/nicegui/milestone/169 so feel free to look at it yourself. I can say the HMW statement is: "how might we help Falko with finding out ones best not in 3.13, or reviewing the PRs if they are really for 3.13" I don't have a systemized way of doing this, though. If anything you should not fully listen to me and become another Evan because Falko is a very systemized person and I'm not (don't ask how we get along, that's a long story) @falkoschindler do you wanna guide him a bit in the meantime? Actually @HosseyNJF general "what should I do as an open source contributor" gets you a long way. Some braindump:
Final note: not all open source repo keep the release milestone decision making process open. So "what should I do as an open source contributor" might not get you all the way. And I also think it's intentional because otherwise we feel kinda bad for just taking your code but looping you out of all decision making process? |
|
Thanks a lot for this pull request, @HosseyNJF! I like the idea of splitting And thanks for offering your help! This is very appreciated! Rather than answer one-on-one, we wrote up where contributions are most valuable right now: #6094. The 3D scene is clearly an area you know well, so pre-flighting and helping unblock scene-related PRs would be a natural fit — but anything on that list genuinely helps. 🙏 |

Motivation
The NiceGUI 3D scene class has a lot of potential, but it's severly limited by the fact that users cannot create their own custom meshes inside JS, just like they do with Vue components. With this PR, users can create any complex meshes they need in JS directly, integrate any library authored for three.js into their objects, and even go as far as integrating a pre-existing three.js project into NiceGUI by just importing the project as a singular "Object3D" and exposing methods for the Python
run_method.Relevant: #4120
Implementation
The idea is to let children of the "Object3D" class define a "component" which gets registered as a library in the
dependenciesmodule, and loaded in the importmap. Then, thescene.jsfile imports those libraries, and hooks into them at various points (for creation, attaching, detaching, etc). This will allow a modular system where each component's code is encapsulated in a JS file.As a side-effect, all pre-defined objects were also refactored to use this new system.
I still haven't figured out how to make the connection from JS -> Python more clear, for example letting components define their own events and emit them.
Progress