Skip to content

refactor(events)!: source-agnostic pointer system (Pointer + EventRaycaster + DOMPointerManager)#66

Merged
bigmistqke merged 6 commits into
solidjs-community:next-cleanupfrom
bigmistqke:events
Jun 5, 2026
Merged

refactor(events)!: source-agnostic pointer system (Pointer + EventRaycaster + DOMPointerManager)#66
bigmistqke merged 6 commits into
solidjs-community:next-cleanupfrom
bigmistqke:events

Conversation

@bigmistqke

@bigmistqke bigmistqke commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

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 single onPointer* family (the redundant onMouse* 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 an Object3D's world transform (controller).
  • DOMPointerManager — the built-in screen source: one Pointer per native pointerId (independent multi-touch) plus a primary Pointer for 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 + ControllerRaycaster
  • feat(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 pointerId

Breaking change

Dispatch is driven by DOMPointerManager + Pointer; the onMouse* handler family and the legacy raycaster.update() are removed.

Test plan

  • full suite green at this commit (ec8df05)

…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.
@pkg-pr-new

pkg-pr-new Bot commented Jun 5, 2026

Copy link
Copy Markdown

commit: ec8df05

@bigmistqke bigmistqke merged commit c5db8e2 into solidjs-community:next-cleanup Jun 5, 2026
2 checks passed
@bigmistqke bigmistqke deleted the events branch June 5, 2026 16:50
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
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.
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