Skip to content

perf(transform): scale-only path, eager allocation, contain cache#14

Merged
chiefcll merged 1 commit into
mainfrom
perf/transform-fast-path-followups
May 11, 2026
Merged

perf(transform): scale-only path, eager allocation, contain cache#14
chiefcll merged 1 commit into
mainfrom
perf/transform-fast-path-followups

Conversation

@chiefcll
Copy link
Copy Markdown
Contributor

Summary

Stacked on top of #13. Follow-ups to the translate-only fast path:

  • fix: eliminate props divergence between CoreNode and CoreTextNode #3 — scale-only branch + Matrix3d.rotate(0) guard: Matrix3d.rotate now skips Math.cos(0)/Math.sin(0) (neither V8 nor JSC constant-folds them) and writes an identity directly. updateLocalTransform splits the rotation/scale logic into three branches — rotation (full multiply path), scale-only (4-mul in-place .scale()), and translate-only. Avoids building a separate scaleRotate matrix and collapses the 8-mul multiply to 4 muls for the common UI-animation case of scale without rotation.
  • chore: remove dead orphaned textures management #6 — eager allocation + stop reassigning: CoreNode now allocates localTransform and globalTransform as identity matrices in the constructor. The Global block reuses these instances via Matrix3d.copy(src, dst) instead of reassigning the field, keeping the field's hidden class stable. Dead parent.globalTransform || lt and if (gt === undefined) fallbacks are removed. _localIsTranslate now defaults to true since the eagerly-allocated matrix is already identity-shape, so the very first update takes the fast path. Stage root init copies in place into the eagerly-allocated globalTransform.
  • fix: bake node color into canvas texture to preserve emoji colors #4 — cached _hasContainResize: updateIsSimple computes the boolean once when texture/textureOptions change; updateLocalTransform reads the flag instead of running the optional-chain + string compare on every Local update.

Test plan

  • pnpm test — 132/132 passing
  • pnpm build — clean
  • Lint (prettier + eslint) clean on changed files
  • 12 new unit tests covering Matrix3d.rotate(0) identity output and reset semantics, scale-only path output (ta/td set, tb/tc untouched) including pivot algebra, constructor-time matrix allocation and instance reuse across simple/non-simple frames, and _hasContainResize flag transitions
  • Visual regression — recommend running locally before merge

Note: base branch is #13. Rebase onto main once #13 lands.

🤖 Generated with Claude Code

Base automatically changed from perf/transform-fast-path to main May 11, 2026 14:05
Follow-ups to the translate-only fast path:

1. Matrix3d.rotate(angle, out): guard angle===0 to skip Math.cos(0)/sin(0)
   and write an identity directly. Matches the existing instance-method
   guard.

2. updateLocalTransform: split rotation/scale into three branches —
   rotation (full multiply path), scale-only (4-mul .scale() in place),
   and translate-only. Avoids building a separate scaleRotate matrix and
   collapses the 8-mul multiply to 4 muls for the common UI-animation
   case of scale without rotation.

3. CoreNode now eagerly allocates localTransform and globalTransform
   as identity matrices in the constructor. The Global block reuses
   these instances via Matrix3d.copy(src, dst) instead of reassigning
   the field, keeping the field's hidden class stable. The dead
   `parent.globalTransform || lt` and `if (gt === undefined)` fallbacks
   are removed. _localIsTranslate now defaults to true since the eagerly
   allocated matrix is already identity-shape, so the very first update
   takes the fast path.

4. _hasContainResize cached on the node: updateIsSimple computes it once
   when texture/textureOptions change, and updateLocalTransform reads
   the boolean instead of running the optional-chain + string compare
   on every Local update.

Stage root init updated to copy in place into the eagerly-allocated
globalTransform rather than reassigning.

Adds 12 unit tests covering: Matrix3d.rotate(0) identity output and
reset semantics, scale-only path output (ta/td set, tb/tc untouched)
including pivot algebra, constructor-time matrix allocation and
instance reuse across simple/non-simple frames, and _hasContainResize
flag transitions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@chiefcll chiefcll force-pushed the perf/transform-fast-path-followups branch from 0da91e2 to 52d2c5d Compare May 11, 2026 14:08
@chiefcll chiefcll merged commit 847e42f into main May 11, 2026
1 check passed
@chiefcll chiefcll deleted the perf/transform-fast-path-followups branch May 11, 2026 14:13
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.

1 participant