refactor(events)!: source-agnostic pointer system (Pointer + EventRaycaster + DOMPointerManager)#66
Merged
Conversation
…ointer* family) Ports the hover/missable/default dispatch from the per-kind registries into one per-pointer Pointer class with its own hover state, fed by a manager's raycaster. Adds context.eventRegistry (the single registry the Pointer raycasts; populated in a later task). Additive + unwired — existing suite unchanged (175/2 → +5).
…ster cast(registry, context) aims the ray and intersects (ported from the old raycast); ScreenRaycaster adds setCursor; ControllerRaycaster casts from a space's matrixWorld. Legacy update() kept (now optional) so the pre-Pointer engine still runs. Additive.
…d + primary) Owns the canvas listeners, a Pointer per native pointerId (multi-touch), and a primary Pointer for the family-agnostic click/dblclick/contextmenu/wheel gestures. Additive — not yet wired (the clean cut replaces createEvents next).
…op onMouse* createEvents now registers handler-bearing objects into the single context.eventRegistry and connects the DOMPointerManager (per-pointerId Pointers + a primary Pointer for click/wheel). Deletes the three per-kind registries, the old raycast, eventNameMap, createRegistry, and the duplicated createThreeEvent. BREAKING: onMouse* handlers removed (redundant with onPointer*; absent from r3f). Their test blocks are removed; every other test passes unchanged (185 → 172), confirming the new dispatch is behavior-identical for the mouse path.
The pre-Pointer engine was the only caller; cast() replaces it. Drops update() from EventRaycaster + Cursor/CenterRaycaster and the unused RayEvent type; migrates the two api-coverage tests that probed update() to the setCursor/cast API.
Open
2 tasks
commit: |
2 tasks
bigmistqke
added a commit
that referenced
this pull request
Jun 5, 2026
…ods + typing (#67) **Act 2 of 3** (follows #66, now merged). Adds the plugin seam that Act 3 (XR as a plugin) builds on. Squash-merges to one commit on `next-cleanup`. ## Summary Adds a typed plugin system so `createT`/`<Entity>` can be extended with contributed props and methods, with no overhead when unused: - **`plugin()`** — global / class-filter / type-guard forms, plus the type machinery. - **`resolvePluginMethods`** + **`applyProp` routing** — contributed methods run instead of instance assignment; `createT` resolves plugins per element, gated by `plugins.length` (a no-plugin namespace never touches the path). - **`Props<T, TPlugins>`** surfaces contributed methods as inferred-typed props; enforced `<Entity plugins>` via `UnionToIntersection` over a readonly tuple. - **`Context.initializePlugin` + `meta.ctx`** give plugin code its mount-site context. - exports `plugin()` from the package entry. ## Commits (10) `minimal plugin seam foundation` · `plugin() forms + type machinery` · `resolvePluginMethods` · `applyProp routing + per-element resolve (gated)` · `Props<T, TPlugins>` · `typed+enforced <Entity plugins>` · `PropsWithPlugins helper` · `rename Props->BaseProps` · `Context.initializePlugin + meta.ctx` · `export plugin()` ## Test plan - [x] full suite green at this commit - [x] benchmarked perf-neutral vs no-plugin (vsync-uncapped scenes, up to ~3,900 nodes): plugin-enabled matches the baseline within noise
4 tasks
bigmistqke
added a commit
that referenced
this pull request
Jun 6, 2026
…ride typing (#68) ## Summary The #66 events rewrite and the #67 plugin system both shipped without their doc updates — the site was describing an API that no longer exists and a feature that was never documented. This clears that debt, adds an interactive plugins tour chapter, and fixes one plugin-typing bug the demo surfaced. ## Stale docs corrected (#66) - **`events/overview`** — drops the `onMouse*` family (removed in #66; only `onPointer*` / `onClick` / `onWheel` remain) from the supported, stoppable, and non-stoppable lists and the event-applicability table. - **`utilities/raycasters`** — the page documented `EventRaycaster.update(event, context)`, which #66 deleted. Rewritten around the real `cast(registry, context)` interface, with a corrected custom-raycaster example and new sections for `ScreenRaycaster` and `ControllerRaycaster`. ## Plugins documented (#67) - **`utilities/plugin`** — new API page: what a plugin is, the three `plugin()` forms (global / class-filtered / type-guard), registration via `createT` and `<Entity plugins>`, and the typed contributed-prop guarantee. - **Tour chapter 09 "Plugins"** — builds a `lookAt` plugin from the "props set properties, they don't call methods" motivation, ending in a live demo: a field of cones that turn to face the pointer. Inserted before the WebGPU peek (renumbered 09 → 10 so the peek stays the finale); chapter 08's close now hands off to it. ## Library fix: contributed props override native members Writing the `lookAt` demo surfaced a bug in the #67 plugin typing. A plugin intercepts its prop at runtime (`applyProp` checks `pluginMethods` first), so a contributed prop should be able to reuse a native member's name — e.g. `lookAt` driving `Object3D.lookAt`. But `Props` *intersected* the contributed type with the base, producing `nativeMethod & V`, which no value satisfies, so `<T.Mesh lookAt={vec} />` failed to type-check even though it worked at runtime. `Props` now drops the contributed keys from `BaseProps` before adding them, so the contributed type *replaces* the native one — matching the runtime. Guarded so the common no-plugins case is untouched (the loose default `readonly Plugin[]` has `length: number`; only a real inferred tuple contributes override keys). Regression test added. This is what lets the tour demo use the natural `lookAt` prop name. ## Test plan - [x] `pnpm build` + `pnpm lint` (circular + eslint + types) green. - [x] Browser suite green, incl. a new test that a `Vector3` is assignable to a contributed `lookAt` prop. - [x] lookAt demo verified in-browser — cones point at the cursor and track it. - [x] Dev server: no more mid-session re-optimize / reload after the `optimizeDeps.include` change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Act 1 of 3 splitting #65 into reviewable, independently-green slices that land as three squash-merged commits on
next-cleanup. This one is self-contained; Act 2 (plugin system) and Act 3 (XR as a plugin) follow once this merges.Summary
Replaces the DOM-coupled per-kind event registries with a layered, source-agnostic pointer system that any source can drive:
Pointer— per-pointer, DOM-agnostic dispatch over a singleonPointer*family (the redundantonMouse*family is gone), tracking its own hover state so multiple pointers stay independent.EventRaycaster.cast+ScreenRaycaster+ControllerRaycaster— the ray strategy, aimed from a 2D cursor (screen) or anObject3D's world transform (controller).DOMPointerManager— the built-in screen source: onePointerper nativepointerId(independent multi-touch) plus aprimaryPointerfor the family-agnostic click/dblclick/contextmenu/wheel gestures.Commits (6)
feat(events): Pointer — per-pointer DOM-agnostic dispatch (single onPointer* family)feat(events): EventRaycaster.cast + ScreenRaycaster + ControllerRaycasterfeat(events): DOMPointerManager — screen pointer source (per-pointerId + primary)refactor(events)!: drive dispatch via DOMPointerManager + Pointer; drop onMouse*refactor(events): remove dead legacy raycaster.update()test(events): multi-touch — independent hover/leave per pointerIdBreaking change
Dispatch is driven by
DOMPointerManager+Pointer; theonMouse*handler family and the legacyraycaster.update()are removed.Test plan
ec8df05)