Repository navigation
bump v2.1.12 - #45
bump v2.1.12#45
Conversation
📝 WalkthroughWalkthroughThis PR bumps the Unicorn Studio SDK version from 2.1.9 to 2.1.12, updating the version constant, package metadata, and the vendor library file. The vendor library undergoes a substantial internal refactor affecting texture handling, interpolation/animation, rendering pipeline, and state management. ChangesVersion Bump & Vendor Update
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
vendor/unicornstudio/unicornStudio.umd.js (1)
2713-2726:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winRemove the call to the nonexistent
_dispose()helper.Line 2714 invokes
r._dispose(), but this bundle only definesTexture.remove(). Hitting the!i && r._copiedFrombranch will throw before the replacement texture is created.Suggested fix
if (!i && r._copiedFrom) { - (r._dispose(), (e.textures = e.textures.filter((e) => e !== r))); + e.textures = e.textures.filter((e) => e !== r); const i = e.createTexture({ sampler: t, premultiplyAlpha: !0 }); return (🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@vendor/unicornstudio/unicornStudio.umd.js` around lines 2713 - 2726, The code calls the nonexistent helper r._dispose() inside the branch guarded by r._copiedFrom, which will throw; replace that call with the defined removal method (call r.remove() or Texture.remove() on the texture instance) and keep the subsequent e.textures = e.textures.filter((e) => e !== r) and the call to e.createTexture({ sampler: t, premultiplyAlpha: !0 }) intact so the old texture is removed using the correct API before creating the replacement; ensure the reindexing helper that sets t.index and calls t._setTextureUniforms() (the inline function after createTexture) remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@vendor/unicornstudio/unicornStudio.umd.js`:
- Around line 6815-6820: The global destroy function iterates directly over the
mutable array ye so scene.destroy() calls can remove items and cause some scenes
to be skipped; fix e.destroy by iterating over a snapshot copy of ye (e.g.,
create a shallow copy before the loop) or by draining ye in a loop (pop/shift)
to ensure every registered scene gets destroy() called, then clear ye.length = 0
and call Ee() as before. Reference: the e.destroy function, the ye array and the
Ee() call.
- Around line 6823-6866: The init() loop can hang and wrongly mark nodes
initialized; fix by first computing the filtered node list (const pending =
Array.from(document.querySelectorAll(...)).filter(n =>
!n.getAttribute('data-us-initialized'))), immediately resolve the Promise if
pending.length === 0, then for each pending element call
requestIdleCallback(...) that invokes Me(...) but only
setAttribute('data-us-initialized', 'true') after Me resolves successfully;
track completions with a remaining counter or use Promise.allSettled on the
array of Me(...) promises so the outer Promise always settles even if some Me
calls reject, and ensure the success-resolve condition uses the pending list
length (not the original i.length) so the caller is never left hanging.
---
Outside diff comments:
In `@vendor/unicornstudio/unicornStudio.umd.js`:
- Around line 2713-2726: The code calls the nonexistent helper r._dispose()
inside the branch guarded by r._copiedFrom, which will throw; replace that call
with the defined removal method (call r.remove() or Texture.remove() on the
texture instance) and keep the subsequent e.textures = e.textures.filter((e) =>
e !== r) and the call to e.createTexture({ sampler: t, premultiplyAlpha: !0 })
intact so the old texture is removed using the correct API before creating the
replacement; ensure the reindexing helper that sets t.index and calls
t._setTextureUniforms() (the inline function after createTexture) remains
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dc998a78-b8fc-49dc-9fc2-6db67c46aa30
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (5)
CHANGELOG.mdpackage.jsonsrc/shared/constants.tssrc/shared/sdk-bundle.tsvendor/unicornstudio/unicornStudio.umd.js
| (e.destroy = function () { | ||
| (pe.forEach((e) => { | ||
| (ye.forEach((e) => { | ||
| e.destroy(); | ||
| }), | ||
| (pe.length = 0), | ||
| ye()); | ||
| (ye.length = 0), | ||
| Ee()); |
There was a problem hiding this comment.
Iterate over a snapshot in the global destroy() path.
Each scene's destroy() removes itself from ye, so ye.forEach(...) can skip entries when more than one scene is registered. That leaves some scenes undisposed.
Suggested fix
(e.destroy = function () {
- (ye.forEach((e) => {
+ (ye.slice().forEach((e) => {
e.destroy();
}),
(ye.length = 0),
Ee());
}),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| (e.destroy = function () { | |
| (pe.forEach((e) => { | |
| (ye.forEach((e) => { | |
| e.destroy(); | |
| }), | |
| (pe.length = 0), | |
| ye()); | |
| (ye.length = 0), | |
| Ee()); | |
| (e.destroy = function () { | |
| (ye.slice().forEach((e) => { | |
| e.destroy(); | |
| }), | |
| (ye.length = 0), | |
| Ee()); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vendor/unicornstudio/unicornStudio.umd.js` around lines 6815 - 6820, The
global destroy function iterates directly over the mutable array ye so
scene.destroy() calls can remove items and cause some scenes to be skipped; fix
e.destroy by iterating over a snapshot copy of ye (e.g., create a shallow copy
before the loop) or by draining ye in a loop (pop/shift) to ensure every
registered scene gets destroy() called, then clear ye.length = 0 and call Ee()
as before. Reference: the e.destroy function, the ye array and the Ee() call.
| return ( | ||
| we(), | ||
| new Promise((e, t) => { | ||
| const i = [ | ||
| ...document.querySelectorAll( | ||
| "[data-us-project], [data-us-project-src]", | ||
| ), | ||
| ], | ||
| s = | ||
| "undefined" != typeof window && window.requestIdleCallback | ||
| ? window.requestIdleCallback | ||
| : (e) => setTimeout(e, 0); | ||
| i.filter((e) => !e.getAttribute("data-us-initialized")).forEach( | ||
| (t, a) => { | ||
| (t.setAttribute("data-us-initialized", !0), | ||
| s(() => { | ||
| const s = O(t, "data-us-project"), | ||
| r = O(t, "data-us-project-src"), | ||
| n = O(t, "data-us-disablemobile"), | ||
| l = O(t, "data-us-disablemouse"); | ||
| Me({ | ||
| projectId: r ? null : s, | ||
| filePath: r, | ||
| element: t, | ||
| dpi: +O(t, "data-us-dpi"), | ||
| scale: +O(t, "data-us-scale"), | ||
| production: O(t, "data-us-production"), | ||
| fps: +O(t, "data-us-fps"), | ||
| lazyLoad: O(t, "data-us-lazyload"), | ||
| altText: O(t, "data-us-alttext"), | ||
| ariaLabel: O(t, "data-us-arialabel"), | ||
| fixed: O(t, "data-us-fixed"), | ||
| interactivity: | ||
| n || l | ||
| ? { mouse: { disableMobile: n, disabled: l } } | ||
| : null, | ||
| }).then((t) => { | ||
| a === i.length - 1 && e(ye); | ||
| }); | ||
| })); | ||
| }, | ||
| ); | ||
| }) | ||
| ); |
There was a problem hiding this comment.
init() can leave callers hanging and permanently mark failed nodes as initialized.
This async loop never settles in several common cases: zero pending nodes, any already-initialized node (because a is compared against i.length instead of the filtered length), or any Me(...) rejection. Setting data-us-initialized before success also prevents retrying a failed scene.
Suggested direction
(e.init = function () {
return (
we(),
new Promise((e, t) => {
- const i = [
+ const i = [
...document.querySelectorAll(
"[data-us-project], [data-us-project-src]",
),
],
+ pending = i.filter((e) => !e.getAttribute("data-us-initialized")),
s =
"undefined" != typeof window && window.requestIdleCallback
? window.requestIdleCallback
: (e) => setTimeout(e, 0);
- i.filter((e) => !e.getAttribute("data-us-initialized")).forEach(
- (t, a) => {
- (t.setAttribute("data-us-initialized", !0),
- s(() => {
- const s = O(t, "data-us-project"),
- r = O(t, "data-us-project-src"),
- n = O(t, "data-us-disablemobile"),
- l = O(t, "data-us-disablemouse");
- Me({
- projectId: r ? null : s,
- filePath: r,
- element: t,
- dpi: +O(t, "data-us-dpi"),
- scale: +O(t, "data-us-scale"),
- production: O(t, "data-us-production"),
- fps: +O(t, "data-us-fps"),
- lazyLoad: O(t, "data-us-lazyload"),
- altText: O(t, "data-us-alttext"),
- ariaLabel: O(t, "data-us-arialabel"),
- fixed: O(t, "data-us-fixed"),
- interactivity:
- n || l
- ? { mouse: { disableMobile: n, disabled: l } }
- : null,
- }).then((t) => {
- a === i.length - 1 && e(ye);
- });
- }));
- },
- );
+ if (!pending.length) return e(ye);
+ Promise.all(
+ pending.map(
+ (node) =>
+ new Promise((resolve, reject) => {
+ s(() => {
+ const projectId = O(node, "data-us-project"),
+ filePath = O(node, "data-us-project-src"),
+ disableMobile = O(node, "data-us-disablemobile"),
+ disableMouse = O(node, "data-us-disablemouse");
+ Me({
+ projectId: filePath ? null : projectId,
+ filePath,
+ element: node,
+ dpi: +O(node, "data-us-dpi"),
+ scale: +O(node, "data-us-scale"),
+ production: O(node, "data-us-production"),
+ fps: +O(node, "data-us-fps"),
+ lazyLoad: O(node, "data-us-lazyload"),
+ altText: O(node, "data-us-alttext"),
+ ariaLabel: O(node, "data-us-arialabel"),
+ fixed: O(node, "data-us-fixed"),
+ interactivity:
+ disableMobile || disableMouse
+ ? { mouse: { disableMobile, disabled: disableMouse } }
+ : null,
+ })
+ .then((scene) => {
+ node.setAttribute("data-us-initialized", !0);
+ resolve(scene);
+ })
+ .catch((error) => {
+ node.removeAttribute("data-us-initialized");
+ reject(error);
+ });
+ });
+ }),
+ ),
+ ).then(() => e(ye), t);
})
);
}),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vendor/unicornstudio/unicornStudio.umd.js` around lines 6823 - 6866, The
init() loop can hang and wrongly mark nodes initialized; fix by first computing
the filtered node list (const pending =
Array.from(document.querySelectorAll(...)).filter(n =>
!n.getAttribute('data-us-initialized'))), immediately resolve the Promise if
pending.length === 0, then for each pending element call
requestIdleCallback(...) that invokes Me(...) but only
setAttribute('data-us-initialized', 'true') after Me resolves successfully;
track completions with a remaining counter or use Promise.allSettled on the
array of Me(...) promises so the outer Promise always settles even if some Me
calls reject, and ensure the success-resolve condition uses the pending list
length (not the original i.length) so the caller is never left hanging.



Summary by CodeRabbit