All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
Breaking Change: When referencing the objects managed by other elements -- like a custom camera, or a geometry or material you want to reuse across multiple meshes -- you now have to prefix the attribute with the new
ref:
directive:<three-mesh ref:geometry="#my-geometry" ref:material="#my-material"></three-mesh>
-
Breaking Change:
<three-web-gl-renderer>
now is<three-webgl-renderer>
. -
New: GLTF loading & rendering! We now provide a new
@three-elements/loaders
package that will house a series of extra elements that can load 3D models in various formats via HTTP and render them, starting with the<three-gltf-asset>
element:<three-gltf-asset url="models/spaceship.gltf"></three-gltf-asset>
-
New: Texture loading! The
<three-texture>
element now accepts aurl
attribute that will make it load a texture from the specified URL:<three-mesh-standard-material> <three-texture url="texture.jpg" attach="map"></three-texture> </three-mesh-standard-material>
-
New: Text Rendering! We now provide a
@three-elements/text
package that provides text rendering capabilities via a<three-text>
element. This functionality is powered by the troika-three-text library.<three-text rotation.z="20deg" text="Lorem ipsum dolor sit amet?" anchor-x="50%" anchor-y="50%" material.color="hotpink" font-size="1.2" ></three-text>
-
New: Opt-in attribute observing! You can now set the
observed
attribute on the<three-game>
tag to make it monitor changed attributes using a MutationObserver. This is useful if you want to edit the DOM of a project directly in your browser's devtools; other than that, it serves no real purpose. Please keep in mind that enabling this flag has a very high performance cost; for this reason, we're also making it log a warning when enabled. -
New: Experimental Preact Bindings! We now provide a
@three-elements/preact
package that provides some light-weight bindings for use in Preact applications using its hyperscript syntax. This makes use of an experimental new proxy generator (housed in the equally new@three-elements/proxy
package) that can be used to create three-elements bindings for all sorts of web frameworks, so expect to see more of this in the future.
-
Fixed: When switching a scene to a new camera, this new camera would not be picked up by the scene's pointer event manager, pretty much breaking pointer interactions for the entire scene. This has now been resolved.
-
Fixed: Pointer event handling has been made significantly more reliable.
- Changed: The repository has been converted into a monorepo to provide a better structure for the packages that we already have, and a nicer home for the packages we will be adding in the future.
-
Breaking Change: Ticker events have been completely reimplemented from scratch. The DOM events we were dispatching in an earlier version have been replaced by an internal event emitter, yielding significant (multliple orders of magnitude) performance gains. Because we are no longer using DOM events, the properties and attributes that allow you to hook callbacks into the ticker have been renamed to
tick
,lateTick
,frameTick
andrenderTick
, with their corresponding attributes now namedtick
,late-tick
,frame-tick
andrender-tick
.Ticker callback code that is passed via string attributes is run as the body of a function where
this
is the element itself,object
is the object the element is managing, anddt
is the current frame's delta time value:<three-mesh tick="object.rotateZ(2 * dt)"></three-mesh>
When directly assigning functions to these properties, they will now receive the delta time and a reference to the element itself as arguments. For example, in lit-html, you can now do this:
html` <three-mesh .tick=${(dt, { object }) => object.rotateZ(5 * dt)}></three-mesh> `
Please refer to the documentation for details on how to use these!
-
New: When assigning to an object property via an attribute, you can now set the attribute to a CSS selector to reference another object. This can, for example, be used to re-use geometries, materials and other potentially expensive resources:
<!-- Resources --> <three-box-buffer-geometry id="geometry"></three-box-buffer-geometry> <three-mesh-standard-material id="material" color="#555"></three-mesh-standard-material> <!-- Scene Contents --> <three-mesh position="-2, 0, 0" geometry="#geometry" material="#material"></three-mesh> <three-mesh position="0, 0, 0" geometry="#geometry" material="#material"></three-mesh> <three-mesh position="2, 0, 0" geometry="#geometry" material="#material"></three-mesh>
-
New: When working with plain string attributes, you can now use the
deg
suffix to convert the specified value into radians. This is very useful in 100% HTML-based projects where you don't have access to JavaScript'sMath.PI
:<three-mesh rotation.x="-90deg">...</three-mesh>
-
New: You can now configure custom renderers! Just like with any other element provided by this library, you can use attributes to configure them to your needs:
<three-game> <three-web-gl-renderer xr.enabled></three-web-gl-renderer> <three-scene> ... </three-scene> </three-game>
Renderers that are part of the THREE.* namespace are supported out of the box; support for SVG and CSS renderers will come in a future update.
-
New: You no longer have to use valid JSON syntax for
arg
attributes -- just provide a list of comma-separated values:<three-fog args="#333333, 1, 1000"></three-fog>
The commas, in fact, are now purely optional. This will also work:
<three-fog args="#333333 1 1000"></three-fog>
-
New:
<three-game>
now dispatches aready
event you can hook your game's initialization code into. -
New: We now publish a full API Reference. Enjoy!
-
Changed: By popular request, three-elements will no longer log to the console on startup. Enjoy the quiet!
-
Changed: The core ticker loop now makes use of
setAnimationLoop
instead ofrequestAnimationFrame
, which is a critical prerequisite for making your three-elements project WebXR-ready. -
Changed: When attributes on an element map to a non-existing property on the wrapped object, there will no longer be a warning logged to the console. (This is very useful when you're combining three-elements with other frameworks that make use of their own attribute names on your elements.)
-
Fixed: When assigning attributes a value of "0", this will now correctly assign the parsed numerical value of 0 to the corresponding property, not a string representation of it. Programming, how does it work?
-
Fixed: Orthographic cameras now have their frustums and projection matrices updated when the viewport is resized.
-
Fixed: When using the
attach
attribute, a valid candidate element to attach to is now searched for across the boundaries of Shadow DOMs. If this sentence makes any sense to you, I bow to you, for we are united in this madness. -
Fixed: Many little odds and ends, especially with regard to framework interoperability.
If you've been extending ThreeElement in your own code, or hacking on the codebase itself, please note the following changes:
-
New: All element logic that does not deal with managing a wrapped Three.js object has been moved to a new base class called
BaseElement
thatThreeElement
now extends.BaseElement
performs lifecycle management, ticker event handling and other base functionality. -
Breaking Change:
readyCallback
was renamed tomountedCallback
to better reflect when this callback is invoked. -
New: The
BaseElement
class now also provides aremovedCallback
method that will be invoked when we know the element is being removed from the DOM entirely, not just moved to a new parent (as is often the case when pairing three-element with a web application framework.) -
Changed: Instead of using a MutationObserver instance to monitor the element for updated attributes (we can't feasibly make use of
observedAttributes
, remember?), we now simply hook intosetAttribute
to react on attribute changes. This yields significant (order of a magnitude) performance improvements in projects that go through element attributes a lot. Sadly, it also means that changes you're making to the DOM in your browser's dev tools will no longer be picked up automatically (but this feature may make a comeback at a later date.) -
Changed:
yarn dev
now makes use of the excellent @web/dev-server. This allows us to get rid of the importmap shim we had been using so far, load additional dependencies straight from our ownnode_modules
, and greatly increase iteration speed during development. -
Holy Crap:
applyProps
was refactored to useif
instead ofswitch (true)
. All you Senior JavaScript Architects can finally calm down, for I am no longer impeding upon your creed!
- Fixed: Compatibility with recently released Three.js r125!
-
New: Elements now emit
connected
,ready
anddisconnected
lifecycle events that bubble up the DOM tree. -
New: Elements now expose the
requestFrame
function directly, making it a bit more convenient to request a new frame to be rendered (you no longer have to find the game object.) -
Breaking Change: 💥 Completely revamped the ticker system to make it easier to use, and make three-elements more straight-forward to integrate with web application frameworks:
- Ticker callbacks have been renamed from
onupdate
,onlateupdate
,onframe
andonrender
toontick
,onlatetick
,onframetick
andonrendertick
. - Ticker events now are normal CustomEvents, meaning that you would implement callbacks like any other DOM event callback, eg. either as an attribute,
ontick="console.log('sup')"
, or directly setting the property to an event listener function. - You can also directly subscribe to these events through
element.addEventListener
, but in this case you may need to explicitly set the element'sticking
attribute/property to true in order for it to actually connect to the game's ticker. - Ticker events have an
event.detail.deltaTime
property that contains the current frame's delta time. - The
<three-game>
element now also exposes a property nameddeltaTime
that contains the current frame's delta time.
- Ticker callbacks have been renamed from
-
Breaking Change: When setting DOM event handlers through attributes (eg.
onclick="..."
), these will no longer automatically runrequestFrame
for you. -
Breaking Change: Nested properties can now be set using a period separator syntax. Example: the
position.x
attribute will now map toposition.x
. A colon separator (position:x
) is also supported in case a framework is giving you trouble. The previous dashy syntax will now map attributes to their camel-cased counterparts (eg.receive-shadow
will setreceiveShadow
.) -
Breaking Change: When directly assigning a function to the
ontick
,onlatetick
etc. properties, we no longer move heaven and earth to bind that function to the element's scope, which vastly improves interoperability with frontend frameworks that let you set properties directly. -
Changed: You can now set a Three object's mixed-case properties through attributes of the same name, but dasherized. Example: The
cast-shadow
attribute will set thecastShadow
property. -
Fixed:
<three-gltf-asset>
no longer loads the same GLTF twice. -
Fixed:
<three-gltf-asset>
now creates local clones of the loaded GLTF scene (so you can place multiple copies of the same GLTF into your scene.) -
Fixed:
<three-gltf-asset>
now properly forwardscreate-shadow
andreceive-shadow
attributes to the GLTF scene.
- Fixed: compatibility with frameworks that set
ontick
& friends directly as properties (eg. Svelte)
- Fixed: All of the built-in elements now check if they're already defined before attempting to define themselves again. This is useful for development environments with hot reload or HMR, where they would otherwise raise an error about tags already having been defined.
- Changed: The
<three-game>
element now has width: 100%, height: 100% and display: block applied to it by default. If you just plug it into the<body>
, it will use the full display area; if it has a parent element, it will automatically expand its size to fill that. You can, however, also directly style thethree-game
element. The web is a beautiful place!
- First release. Let's do this!