Skip to content

fix(rendering): make SpriteEcsComponent.pivot Y-up to match the rest of the engine - #590

Open
stormmuller wants to merge 1 commit into
devfrom
claude/github-issue-585-7s9m00
Open

fix(rendering): make SpriteEcsComponent.pivot Y-up to match the rest of the engine#590
stormmuller wants to merge 1 commit into
devfrom
claude/github-issue-585-7s9m00

Conversation

@stormmuller

Copy link
Copy Markdown
Member

Summary

SpriteEcsComponent.pivot used a Y-down convention ((0, 0) was the sprite's top-left) while world position, rotation, and every other Y-facing value in the engine are Y-up. The mismatch was an internal projection detail (the vertex shader flips Y before the projection matrix flips it back for position/rotation) leaking through pivot's public API - invisible at the default centered pivot, which is why it survived.

Traced the full pipeline per the issue and confirmed the analysis: bindSpriteInstanceData pre-negates position.world.y and rotation.world to compensate for the projection's Y flip, but sprite.vert.glsl computes the pivot-based local offset after that compensation, so it never gets flipped - pivot.y = 0 landed at the sprite's top instead of its bottom.

Changes

  • sprite.vert.glsl: negate a_instancePivot.y alongside the existing [0,1] -> [-1,1] doubling, so pivot's Y now gets the same flip position/rotation already get. (0, 0) is now bottom-left, (1, 1) is top-right.
  • computeNineSliceRegions (compute-nine-slice-regions.ts): updated the region-offset math ((1 - pivot.y) * height - ... instead of pivot.y * height - ...) so nine-slice region placement agrees with the corrected shader convention. The centered pivot (0.5, 0.5) produces identical output before and after (1 - 0.5 === 0.5), so this is a no-op for every sprite in the repo (no demo or test uses a non-centered pivot).
  • sprite-component.ts: updated pivot's JSDoc to describe the new Y-up convention.
  • compute-nine-slice-regions.test.ts: replaced the single top-left-pivot test with a parameterized case pinning all four corners (bottom-left, bottom-right, top-left, top-right), per the issue's test-coverage callout.
  • CHANGELOG.md: added a Fixed entry under [Unreleased], flagged as a breaking change for non-centered pivots.

Related issue(s)

Closes #585

Out of scope

The issue's design doc reference (design/ui-system.md's pivot bridge, from #580) isn't in dev yet, so there's nothing to remove there in this PR.

Verification checklist

  • npm run check-types passes with 0 errors
  • npm test passes (1036 tests)
  • npm run lint passes with 0 errors (pre-existing, unrelated TODO warnings only)
  • npm run cspell passes with 0 errors
  • npm run check-exports passes
  • No public API surface changed beyond pivot's documented semantics - no export changes needed
  • Documentation under /documentation-site/docs/docs - no page documents the pivot convention, so nothing to update
  • No demo uses a non-centered pivot (verified via grep), so no demo code changes; still built /dist, ran documentation-site's typecheck/build, and visually checked the nine-slice and brick-breaker demos in a browser to confirm no regression at the default centered pivot

Changelog

  • Added a bullet under ## [Unreleased]#### Fixed in CHANGELOG.md

Generated by Claude Code

…of the engine

pivot used a Y-down convention ((0, 0) was the sprite's top-left) while
world position, rotation, and every other Y-facing value are Y-up. The
mismatch was an internal projection detail (the shader flips Y) leaking
through pivot's public API, invisible at the default centered pivot.

Flips pivot's Y in sprite.vert.glsl before it's combined with the quad's
local position, and updates computeNineSliceRegions' pivot handling to
match so nine-slice region placement agrees with the corrected shader.

Breaking change for content using a non-centered pivot.

Fixes #585
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@stormmuller

Copy link
Copy Markdown
Member Author

In the ECS demo. The position looks correct, but the rotation looks inverted?

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.

fix(rendering): SpriteEcsComponent.pivot is Y-down while the rest of the engine is Y-up

2 participants