Skip to content

bump v2.1.12 - #45

Merged
diegopeixoto merged 1 commit into
mainfrom
bump-v2.1.12
May 14, 2026
Merged

diegopeixoto merged 1 commit into
mainfrom
bump-v2.1.12

Conversation

@GeorgeHastings

@GeorgeHastings GeorgeHastings commented May 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Chores
    • Updated to version 2.1.12 with Unicorn Studio SDK enhancements including improved texture handling, animation engine updates, asset preloading, and rendering pipeline optimizations.

@coderabbitai

coderabbitai Bot commented May 5, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This 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.

Changes

Version Bump & Vendor Update

Layer / File(s) Summary
Version Constant
src/shared/constants.ts
UNICORN_STUDIO_VERSION updated from "2.1.9" to "2.1.12".
Package Metadata
package.json, CHANGELOG.md
Package version bumped to 2.1.12 and changelog entry added for 2026-05-05 release.
Vendor Library
vendor/unicornstudio/unicornStudio.umd.js
Unicorn Studio UMD refactored with new interpolation/animation engine, enhanced texture handling (public .source alias), dynamic cache logic, model renderer support, and rendering pipeline adjustments; public API surface unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

version-upgrade

Suggested reviewers

  • diegopeixoto

Poem

🐰 A vendor grows, a version climbs,
From .9 to .12, marks the times,
New textures bloom, animations flow,
The Studio dances to and fro,
Momentum spins where easing glows!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'bump v2.1.12' directly and clearly describes the main change: a version bump to 2.1.12, which is reflected across all modified files (package.json, CHANGELOG.md, constants.ts, and vendor files).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bump-v2.1.12

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.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud

sonarqubecloud Bot commented May 5, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Remove the call to the nonexistent _dispose() helper.

Line 2714 invokes r._dispose(), but this bundle only defines Texture.remove(). Hitting the !i && r._copiedFrom branch 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

📥 Commits

Reviewing files that changed from the base of the PR and between 09fc501 and 2b619af.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • CHANGELOG.md
  • package.json
  • src/shared/constants.ts
  • src/shared/sdk-bundle.ts
  • vendor/unicornstudio/unicornStudio.umd.js

Comment on lines 6815 to +6820
(e.destroy = function () {
(pe.forEach((e) => {
(ye.forEach((e) => {
e.destroy();
}),
(pe.length = 0),
ye());
(ye.length = 0),
Ee());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Suggested change
(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.

Comment on lines +6823 to +6866
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);
});
}));
},
);
})
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

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.

@diegopeixoto
diegopeixoto merged commit f775ab5 into main May 14, 2026
4 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 26, 2026
This was referenced Jul 8, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jul 17, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants