Skip to content

[ThreeJs] Add a new ux-threejs package to create/load 3D scene #2672

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: 2.x
Choose a base branch
from

Conversation

sblondeau
Copy link
Contributor

Q A
Bug fix? no
New feature? yes
Docs? yes
Issues Fix #...
License MIT

Hi !
I have created a new experimental Package to integrate three.js 3D library to available Symfony Ux components.
Three.js is a huge library, so I have selected only some key features, the minimal to create a useful 3D scene.
Available features are :

  • Mesh creation : Gometry shape (Box, Sphere, Cylinder and Plane) with Material (color, image texture...)
  • Loading of external complex 3D objects (GTLF format).
  • Minimal animation (rotation, scale, translation)
  • Minimal camera management
  • Minimal Light management (AmbientLight, DirectionalLight).

I think there are a lot of use cases, mostly loading 3D objects or creating simple 3D scenes (we are not talking about creating complex animations or games :-) ).

Here are some examples of what is possible today:

uxthreejs.webm

TODO in this PR :

  • add more PHP tests
  • add JS test (I need help :-))

TODO in next PR

  • add more classes for Geometry, Mesh, Loader
  • make it compatible with Live components
  • handle more advanced animation feature (e.g. with timeline...)
  • handle more interaction with the scene

I hope you will find it interesting for Symfony Ux environment.
There is still a lot of work to implement other three.js features but this PR is a first start.

@carsonbot carsonbot added Feature New Feature Status: Needs Review Needs to be reviewed labels Mar 30, 2025
Copy link

github-actions bot commented Mar 30, 2025

📊 Packages dist files size difference

Thanks for the PR! Here is the difference in size of the packages dist files between the base branch and the PR.
Please review the changes and make sure they are expected.

FileBefore (Size / Gzip)After (Size / Gzip)
Threejs
controller.d.ts Added 1.49 kB / 601 B
controller.js Added 8.39 kB / 2.04 kB

@smnandre
Copy link
Member

Hey! I have to say, this was a nice surprise :)) 🙇

It might take a bit of time to properly review this PR — given the standards of quality, integrity, and security we aim to uphold, we want to make sure everything aligns before moving forward.

Would you mind listing a few concrete use cases that this package helps solve? That would really help with the review process, especially since not everyone is familiar with it on a daily basis.

Also, just to get a broader picture: do you already have a long-term vision for the package? No pressure at all — there's no wrong answer here, it's more of a food-for-thought kind of question.

@sblondeau
Copy link
Contributor Author

@smnandre thanks for your kind feedback.
First, I am not a specialist of three.js, we will maybe need some more expertise.
However, I think there is a lot of use case, few examples :

  • for an e-shop site, visualize products in 3D
  • for a real-estate/architect : 3D visit of a building
  • for scientific purpose : data viz, cartography, molecular visualization...
  • IA generative can now easily create 3D model, it's a nice solution to display results :) example generated by IA in few minutes (3D model and background)
    Capture vidéo du 2025-03-30 22-31-16.webm

For future, as I said there is a lot of three.js feature to implement (more geometry, material). I think we can also improve a lot animation features, and interaction. First big improvement would be to make it compatible with Live components, to allow more interaction with 3D scene.
Right now, it is my very narrow implementation of three.js but I am sure you can add a lot of nice idea to improve it :-)

@sblondeau
Copy link
Contributor Author

Add "skybox" option to material (360 background textures)
skybox.webm

@Kocal
Copy link
Member

Kocal commented Apr 1, 2025

Hey, that's a lot of work! Do you have some code examples to show us?

However, I'm not really sure about making it an UX package, isn't it too niche?

I mean, UX Chart, UX Map, or even the UX TogglePassword have more sense to me to be in UX, and, I believe they are more "useful" and pertinent on Symfony apps than UX ThreeJS can be, even if this package is super cool.

I think it would make more sense to make it an external package, in your GitHub, WDYT?

@sblondeau
Copy link
Contributor Author

sblondeau commented Apr 1, 2025

Hi @Kocal Thanks for your feedback :-)
I give your the code for all examples in the 3 videos above :D

 /** Basic green box */
$threeBox = new Three();
$basicGreenMaterial = new MeshBasic('green');
$box = new Box(3, 2, 2);
$greenBox = new Mesh(
    geometry: $box,
    material: $basicGreenMaterial,
);

$threeBox->addMesh($greenBox);

/** Basic animated green box */
$basicGreyMaterial = new MeshBasic('grey');

$startScene = new Scene(
    material: $basicGreyMaterial,
);

$threeBox2 = new Three();
$threeBox2->setScene($startScene);
$basicGreenMaterial = new MeshBasic('green');
$box = new Box(3, 2, 2);
$greenBox = new Mesh(
    geometry: $box,
    material: $basicGreenMaterial,
    animation: (new Animation())->rotate(rY: 0.01),
);

$threeBox2->addMesh($greenBox);

/** Box with texture */
$crateTexture = new MeshBasic(map: 'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/textures/crate.gif');

$texturedBox = new Mesh(
    geometry: $box,
    material: $crateTexture,
    animation: (new Animation())->rotate(rY: 0.01),
);

$threeBox3 = new Three();
$threeBox3->addMesh($texturedBox);

/** Other geometric shapes */
$threeBox4 = new Three();
$threeBox4->addMesh(new Mesh(
    new Sphere(),
    new MeshPhong('purple'),
));
$threeBox4->addMesh(new Mesh(
    new Plane(5, 5),
    new MeshPhong(color: 'green', doubleSide: true),
));

$cylinderMesh = new Mesh(
    new Cylinder(radiusTop: 0.5, height: 3, openEnded: true),
    new MeshPhong(color: 'yellow', doubleSide: true),
);
$cylinderMesh->setAngle(aX: M_PI_2)->setPosition(1, 1, 1);
$threeBox4->addMesh($cylinderMesh);

/** Other geometric shapes with red ambient light  */
$threeBox5 = new Three();
$threeBox5->setScene($threeBox4->getScene());
$threeBox5->addLight(new AmbientLight('red', 5));

/** Other geometric shapes with directional lights */
$threeBox6 = new Three();
$threeBox6->setScene($threeBox4->getScene());
$threeBox6->addLight(new DirectionalLight('blue', 5, new Vector3(1, 3)));
$threeBox6->addLight(new DirectionalLight('white', 25, new Vector3(0, 0, 2), new Vector3(1, 1, 1)));

/** Loaded model */
$threeBox7 = new Three();
$model = new GLTFModel($assetMapper->getPublicPath('/models/Xbot.glb'), new Vector3(0, 0, 0));
$threeBox7->addModel($model);

/** Animated loaded model */
$threeBox8 = new Three();
$animatedModel = new GLTFModel($assetMapper->getPublicPath('/models/Xbot.glb'), new Vector3(0, 0, 0));
$animatedModel->animation->playClip = 'run';
$threeBox8->addModel($animatedModel);

/** AI generated 3D Model and background scene */
$threeBox9 = new Three(900, 500);
$background = new MeshBasic(
    map: $assetMapper->getPublicPath('/images/back.jpg'),
);

$threeBox9->setScene(new Scene(material: $background));
$model = new GLTFModel(
    $assetMapper->getPublicPath('/models/wizard.glb'),
);

$threeBox9->addModel($model);

/** Model with skybox background scene */
$threeBox10 = new Three(900, 500);
$skybox = new MeshBasic(
    map: $assetMapper->getPublicPath('/images/hall.webp'),
    skybox: true,
);
$threeBox10->setScene(new Scene(material: $skybox));
$model = new GLTFModel(
    $assetMapper->getPublicPath('/models/troll.glb'),
);

$threeBox10->addModel($model);

and in Twig, to render $threeBox

 {{ render_threejs(threebox) }}

I am agree that the project is maybe less popular than Map or ChartJS in the PHP/Symfony community, but it seems more popular globally (105K stars on github, vs 65K for ChartJS or 42K for Leaflet). And I think three.js has a huge number of use cases (load 3D model, data viz, 360 pictures views, design...).
Bring it to Symfony environment could be really great.

The actual code is already a good start, you can easily load existing 3D models and animate them. There are tons of others features in three.js but it is maybe not necessary to implement more :-).

I understand that it could be one more big package to maintain, and it is difficult to have data about potential future uses.
So I let you decide if it worth to go further. Do not hesitate to contact me on slack if you want to discuss about it !

Thanks ;-)

@Kocal
Copy link
Member

Kocal commented Apr 2, 2025

Thanks for the response, that's appreciated!

We talked a bit with @smnandre yesterday, and I think there is a real issue with the approach.

For example, UX Map lets you fill a "create a map, display markers and other stuff" use case, using either Google Maps or Leaflet. It's not a "UX Google Maps" package that reimplements the Google Maps API in PHP in 1-1, with all possible classes, options, methods, etc... :/

Having a "Three.js implementation in PHP" is a no-go for me, but, having dedicated packages (based on Three.js or whatever other libraries) for specific use cases is yes! Like, a package 3D models visualization/interaction, another package for 360° pictures, etc..

Do you see what I mean?

@sblondeau
Copy link
Contributor Author

@Kocal thanks for your feeback. The idea never was to reimplement all threejs classes and options, it would be an endless and certainly impossible work in php.
I have named the project ux-threejs because I have started from Ux-chartjs package (which is not a generic "chart" package but implements only one lib ;-)). We can maybe rename the package to ux-threed of something else, and make is less tied to three.js.

About multiple packages for different use-cases, I understand totally to have simpler, more focused packages, open to several libraries.
But we should definitely brainstorm about it, because it is quite difficult to split the use cases. In example, you can have 2 use cases

  • Load an existing 3D Model
  • Draw a scene with geometric 3D shapes (design, data viz...)
    What about camera/light/background management which can be use in both cases ? or should we remove these features ?
    And it would be impossible to combine loaded 3D model and drawn geometric object ?

I am available to discuss further about it :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New Feature Status: Needs Review Needs to be reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants