Skip to content

feat(three): add Math bridge for Three - #50

Open
krispya wants to merge 2 commits into
mainfrom
feat/three-bridge
Open

krispya wants to merge 2 commits into
mainfrom
feat/three-bridge

Conversation

@krispya

@krispya krispya commented Sep 7, 2026

Copy link
Copy Markdown
Member

Adds a zero-copy bridge for Three while keeping the usual Object3D math interfaces like position, scale, rotation and quaternion synced. No patching, all userland code.

Basically, we take advantage of the fact that the Three Matrix4 are already array backed and directly copied for GPU buffers. We take this over and then replace the Object3D math objects with our own that access the Math tuples via getters and setters. This makes using Math path very fast with a small hit to perf (the cost of accessors) on the Object3D path. In hot paths we get a 1.4-2.7x speedup.

Workload Vanilla three math/three Speedup
Instanced transforms, 10 000 instances 728 µs 318 µs 2.3×
Scene graph, 4 096 nodes (extend) 777 µs 331 µs 2.3×
Scene graph, 4 096 nodes (per-object mirror) 777 µs 284 µs 2.7×
Frustum culling, 4 096 meshes 293 µs 152 µs 1.9×
Vertex transform, 8 481 vertices 127 µs 59 µs 2.2×
Scene graph step + read every position/rotation 820 µs 606 µs 1.4×

The API uses a handle to get the Math tuples associated with the Object3D.

extend(scene);      // returns the scene math-backed
const t = transformOf(mesh);  // { position, rotation, scale, local, world }
vec3.set(t.position, x, y, z);      // the fast path

@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 102c6f2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

A zero-copy bridge to three.js and a scene-wide drop-in that lets math
drive three's transforms.

- bridge: Matrix4.elements is math's Mat4 as-is; helpers for instance
  buffers, attributes, camera frustums and world-space bounding spheres
- extend(scene): every object gets a Transform record of tuples, with
  Vector3/Quaternion/Euler views over them so three's API keeps working.
  The scene's updateMatrixWorld becomes one flat parents-first pass.
  Objects added later join via childadded, subclasses that override
  updateMatrixWorld (Camera, SkinnedMesh) are delegated to, per-node
  matrixAutoUpdate/matrixWorldAutoUpdate/pivot are honored, and
  explicitly written Euler angles survive until the quaternion changes
- transformOf(object), extendObject(object), release, propagate, unextend
- three is an optional peer dependency (>=0.166, where forced updates
  respect matrixWorldAutoUpdate); rollup keeps it external
- labs benches under benches/three (@three) comparing against three's
  own API with outputs asserted equal, plus a vite page for browser runs
- vitest coverage in tst/unit/three against plain three

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
krispya added a commit to krispya/threejs-conf-talk that referenced this pull request Sep 11, 2026
The benchmark overlay now renders inside the stone portal on a dark backing
instead of floating in front of the camera. A benchmarkVariant on Screen
switches between the spider IK comparison with bar columns and a new
math-three-benchmark screen showing instanced transforms, scene graph updates,
and frustum culling timings from pmndrs/math#50. Timeline tests cover the new
screen order through Games and the closing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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