Description
Copilot Issue Summary
click to expand
Description:
The author, trusktr, proposes making the <model>
HTML element more compatible with modern web frameworks like React, Vue, Svelte, and Solid. The current implementation of the <model>
element, specifically its getCamera()
API which returns a JavaScript object instead of an HTMLElement, is not compatible with DOM manipulation tools used by these frameworks. This requires developers to create unnecessary wrappers for each framework to bridge the gap, making the code less maintainable.
Proposed Solutions:
-
DOM-Based API:
- Introduce a more DOM-centric approach where cameras and other 3D elements can be defined and manipulated directly in the DOM.
- Example:
<model> <camera type="perspective" position="10 20 30"></camera> </model>
-
Camera Attributes on
<model>
Element:- Alternatively, allow camera properties to be set as attributes on the
<model>
element. - Example:
<model camera="perspective" camera-position="10 20 30"></model>
- Alternatively, allow camera properties to be set as attributes on the
-
Further Future Development:
- Decouple
<camera>
and<model>
elements to be used within a<scene>
element, allowing for more complex 3D scenes. - Example:
<scene fog="linear" fog-color="pink"> <camera type="perspective" position="..."></camera> <model rotation="..."></model> <model scale="..."></model> <box></box> <sphere></sphere> </scene>
- Decouple
Discussion Points:
- Ensuring compatibility with existing web frameworks.
- Avoiding the need for custom wrappers and simplifying developer workflow.
- Maintaining a DOM-centric approach for better integration with web tools.
- Potential benefits of a standardized 3D API for the web.
The author invites further discussion and collaboration to ideate a future where 3D elements are seamlessly integrated into the web ecosystem with high compatibility and simplicity.
Original content
Hello! I first wrote about this here.
https://twitter.com/trusktr/status/1717795902272974942
I want to open a conversation on how we could make the <model>
element more compatible with today's web frameworks, and how currently it is not.
Note
I work on Lume, HTML elements for 3D rendering, and I have been spent a lot of time imagining what native 3D elements in browsers could be like.
Try viewing and hovering on elements in the devtools element inspector when view examples.
I'll re-post what I wrote on Twitter here, updated and improved a little:
@apple's HTML <model>
element in #visionOS Safari is incredibly neat (see the video, at 12:36), hinting at an awesome future of high-level 3D web capabilities that don't require intimate programming knowledge to use.
It however does not hint at a full HTML 3D future compatible with React, Vue, Svelte, Solid, and all the other DOM tools we've evolved over the years. Let me explaine why, and perhaps we can fix this.
<model>
enables amazing native features for web in a simple way, and starts to paint an awesome future for web, but I believe we can plan our HTML future better based on the present (cc @jensimmons as the curator of our #webdev needs for @WebKit, and @marcoscaceres as editor of the spec):
The current model.getCamera()
API returns a non-HTMLElement plain-JavaScript object, which means all of our DOM-manipulation tools (@buildWithLit, @reactjs, @vuejs, @sveltejs, @solid_js, and more) will not be able to manipulate a <model>
element's camera out of the box using their declarative-reactive templating systems, requiring a non-standard new way of programming interactivity specifically for <model>
. Web devs will build unnecessary wrappers (for every framework!) to bridge this gap, in order to tie <model>
camera interactivity back into our paradigms.
As an example of how unnecessary wrappers would be, react-three-fiber
wraps Three.js to add the declarative-reactive support for Three.js in React because Three.js is not DOM-based (this is not unnecessary for Three.js, but <model>
aims to be a DOM API and makes part of its API necessarily require non-DOM wrappers). The wrappers that people make for <model>
will need to map attributes/properties from their templates to the <model>
's non-DOM camera objects.
With HTML elements (and well-designed Custom Elements), there is no need for wrappers to be made for every framework, all elements typically work out of the box in any web framework (there are a few edge cases, but we've learned to avoid those in design of new HTML elements).
The following HTML interface is an example that would be compatible with the DOM future all frameworks have been building:
<model ...>
<camera type="perspective" position="10 20 30"></camera>
</model>
This is compatible because by making the camera configurable via DOM with HTML support, every web framework can manipulate it out of the box (and not just on the client side, but also on the server side!).
Alternatively, camera attributes on the <model>
element would also be a compatible pattern, and could later be superceded with HTML elements that override the attribute behavior:
<model camera="perspective" camera-position="10 20 30" etc></model>
These designs are compatible with all of today's frameworks because they embrace the DOM tree model that all DOM tools are designed to work with.
The getCamera()
API, though extremely nifty for what it can do, is not compatible because it side-steps the DOM trees that these tools manipulate, which will make our code more WET (less DRY) due to those wrappers we'll need for every framework to connect to <model>
element features (cameras). If the API were to give us elements and attributes (which elements, and which attributes, can be debated), we'd get these connections concisely and for free.
Imagine <model>
comes out in all browsers, and out-of-the-box anyone using any framework can manipulate all aspects of a <model>
scene right away without escaping out of their framework to write custom JavaScript.
With a DOM-based API, the Promise
return would no longer be necessary for getCamera()
, as these plain JS objects will be controlled while their rendering effects are abstracted underneath. The camera DOM can internally proxy to an underlying renderer (out of process or not).
Today, most frameworks practice one-way data flow (except in edge cases as with <input>
s, etc), but the getCamera()
API, besides not being compatible with DOM tools, is a more cumbersome two-way data flow design:
- First, the user has to get a
Promise
and wait for it. With DOM API, users never have to wait for sub-objects (children) to be ready by using Promises returned by the browser. For scenarios involving elements that load assets (f.e.<img>
), browsers fire aload
event when the element has loaded an asset or assets. - Then the user can start to interact with a camera object but not in a standard way (JS only, no compat with tools).
Instead, with a DOM-centric approach, users would be able to simply map their desired state to the DOM (whether attribtues on <model>
or a new element like <camera>
). The user does not need to know when the underlying internal camera is ready for rendering, just like the user does not need to know when a <select>
is ready for rendering: they simply map their state to the DOM, and they expect the display to update. load
events can be emitted to tell users when assets are ready. Promise
is not necessary.
The current getCamera()
essentially creates a new and alternative object model that requires new tooling for all frameworks, yet does not provide a clear benefit that would make this tradeoff worth it.
We can also get creative here, while not veering away from the really great web developer paradigms we already have:
In a further future (and based on my experience making Lume, and knowledge of A-Frame, Trois for Vue, Threlte for Svelte, react-three-fiber for React, and other similar libraries for various frameworks), <camera>
and <model>
can be decoupled from each other, used in a 3D <scene>
, implicitly disabling the <model>
's camera and instead rendering relative to a user-defined <scene>
with custom graphics interspersed with any number of <model>
elements:
<scene fog="linear" fog-color="pink" ...>
<camera type="perspective" position="..."></camera>
<model rotation="..." ...></model>
<model scale="..." ...></model>
<box ...></box>
<sphere ...></sphere>
</scene>
Such a scene as above is fully compatible with web tools that have evolved over so many years of thought.
Changing the <model>
API would be easy, but breaking apps would be extremely difficult. This is why we need to imagine, right now: how do we ensure that the future brings us elements that immediately fit right in with the tools we've worked hard to create?
I would love to help ideate this future. I've started to ideate over at https://lume.io.
I would love to continue this conversation to ensure that we can create a set of 3D elements that meet the needs of the vast majority of web developers in the simplest way possible with highest compatibility with the existing ecosystem.