-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add ESM script for annotations and an example #8202
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new ESM script for creating interactive 3D annotations in PlayCanvas scenes, along with a comprehensive example showcasing the feature on a 3D jet fighter model. The annotation system creates clickable hotspots with tooltips that maintain constant screen-space size and remain visible even when occluded by geometry.
Key Changes
- New
annotation.mjsscript providing theAnnotationclass with hotspot rendering, tooltip display, and event handling - Example implementation demonstrating 7 annotations on a jet fighter model with HDR environment and shadow catching
- Build script enhancement for improved cross-platform spawn compatibility
Reviewed changes
Copilot reviewed 4 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/esm/annotation.mjs | Core annotation script with 3D hotspot rendering, DOM integration, and interactive tooltip system |
| examples/src/examples/misc/annotations.example.mjs | Example showcasing annotations on a 3D jet fighter model with camera controls |
| examples/thumbnails/misc_annotations_small.webp | Small thumbnail image for the annotations example |
| examples/thumbnails/misc_annotations_large.webp | Large thumbnail image for the annotations example |
| examples/scripts/build-thumbnails.mjs | Added shell: true option to spawn for cross-platform compatibility |
| examples/assets/models/jet-fighter.txt | Attribution file for the jet fighter 3D model (CC BY 4.0) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
| this.hotspotDom.addEventListener('click', (e) => { | ||
| e.stopPropagation(); | ||
| this.showTooltip(); | ||
| }); | ||
|
|
||
| const leave = () => { | ||
| if (Annotation.hoverAnnotation === this) { | ||
| Annotation.hoverAnnotation = null; | ||
| this.setHover(false); | ||
| } | ||
| }; | ||
|
|
||
| const enter = () => { | ||
| if (Annotation.hoverAnnotation !== null) { | ||
| Annotation.hoverAnnotation.setHover(false); | ||
| } | ||
| Annotation.hoverAnnotation = this; | ||
| this.setHover(true); | ||
| }; | ||
|
|
||
| this.hotspotDom.addEventListener('pointerenter', enter); | ||
| this.hotspotDom.addEventListener('pointerleave', leave); | ||
|
|
||
| document.addEventListener('click', () => { | ||
| this.hideTooltip(); | ||
| }); |
Copilot
AI
Nov 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Event listeners added to document and this.hotspotDom are not removed during cleanup, causing potential memory leaks. The listeners on lines 413, 433, 434, and 436 should be stored as references and removed in the 'destroy' handler.
Consider storing the handler functions and removing them:
this.clickHandler = (e) => {
e.stopPropagation();
this.showTooltip();
};
this.hotspotDom.addEventListener('click', this.clickHandler);
this.documentClickHandler = () => {
this.hideTooltip();
};
document.addEventListener('click', this.documentClickHandler);
// In destroy handler:
this.hotspotDom.removeEventListener('click', this.clickHandler);
this.hotspotDom.removeEventListener('pointerenter', enter);
this.hotspotDom.removeEventListener('pointerleave', leave);
document.removeEventListener('click', this.documentClickHandler);Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
There are a few simplifications and improvements can be done to these hotspots:
It might sound insignificant, but browsers can be notoriously bad at re-layouting, so even a single extra re-layout of a simple page, can lead to some ms wasted reducing framerate from nicely steady one. Especially with multiple elements updated during requestAnimationFrame. |
|
Hey @Maksims,
|
Got it, I thought that circle was drawn using CSS in 2D.
This will then apply to the popup of an info box. Re-layouting/reflow is a process when browser has to re-calculate a lot of things with DOM due to potentially structure affecting changes in drawing state (top/left - is affecting operations). This means browser will go through all elements, re-calculate it's new bounding boxes, tree, check how they overlap between each other, and re-apply all styles. If this is triggered on every frame - this will is CPU intensive operation, especially on mobile. And will lead to framerate drops. To preserve a good performance, it is essential to avoid re-layouting/reflow. Here is a comprehensive list of things that can trigger it: https://gist.github.com/paulirish/5d52fb081b3570c81e3a This is the reason why we created 2D UI in the first place, as DOM UI - will eventually kill the performance of real-time apps. |
Description
playcanvas-engine-annotations.mp4
Checklist