-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add plugin system #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Conversation
Add createPlugin() builder API that enables type-safe conditional plugins: - createPlugin().extends(Constructor).provide() for filtered plugins - createPlugin().provide() for global plugins - createPlugin(setup).provide() for plugins requiring initialization - Proper context passing from setup to provide functions Refactor EventPlugin to use new builder pattern, eliminating interface duplication and improving developer experience. The new API provides better type inference and cleaner syntax while maintaining full type safety for conditional plugin methods.
- Replace separate .extends() and .filter() methods with unified .prop() - Support three filtering patterns: - Single constructor: .prop(THREE.Mesh, element => ...) - Multiple constructors: .prop([THREE.Camera, THREE.Light], element => ...) - Type guards: .prop((element): element is T => condition, element => ...) - Add generic context typing to PluginBuilder - Update examples to demonstrate all three patterns - Maintain full TypeScript inference and runtime type checking 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Remove separate .provide() method in favor of unified .prop() - Support single argument for global plugins: .prop((element, context) => methods) - Support two arguments for filtered plugins: .prop(filter, methods) - Add proper TypeScript interface with method overloads - Update EventPlugin to use new unified API - Add GlobalPlugin example demonstrating single-argument usage - Fix type inference issues with generic context typing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Replace createPlugin().prop() with direct plugin() calls - Add plugin.setup().then() chain for plugins needing context - Support all filtering patterns directly: - Global: plugin(element => methods) - Constructor: plugin(THREE.Mesh, element => methods) - Array: plugin([THREE.Camera, THREE.Light], element => methods) - Type guard: plugin(typeGuard, element => methods) - Update EventPlugin to use setup chain pattern - Add ContextPlugin example demonstrating setup usage - Maintain backward compatibility with plugin().prop() 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Restructure plugin system with simplified type resolution - Consolidate event types and handlers into event-plugin.ts - Reorganize type definitions for better maintainability - Clean up imports and remove unused type utilities - Update PluginExample with Entity component usage - Rename PluginInterface to PluginFn for clarity - Improve plugin prop type resolution with PluginPropsOf - Move event-related types to their proper location
In #32 I discussed having The setup functions currently do rely on context so they only set once (via a But I would personally prefer if nothing relied on where it is mount. Maybe we can follow the approach of |
- Remove complex overload resolution system in favor of direct inheritance checking. - Remove (element: any): {} fallback overloads from PluginFn signatures - Replace complex ResolvePluginReturn with simple TKind extends P inheritance check - Simplify PluginPropsOf type with inline constraint - Fix JSDoc comment for CameraKind type This eliminates the need for R1-R5 overload complexity while maintaining full functionality through direct type inheritance matching.
b7afd14
to
d0402c9
Compare
- instead of mergeProps, let's just merge it together, this prevents the need for proxies. plugins are not going to be hotly updated, but could be hotly accessed, so it's better to optimize for access.
and various cleanups
Maybe the setup function should be global instead, and not connected to any root. That way they can be initialized from the start and are not context dependent. The
SolutionOne solution would be for the EventPlugin to do rely on context, but to be very explicit about it: const { T, Canvas } = createT(THREE, [EventPlugin])
return <Canvas>
<EventPlugin.Provider>
...
</EventPlugin.Provider>
</Canvas> Then at least the API communicates what it can and cannot do. Then maybe we can remove We could add API to prevent deep nesting of contexts: const { T, Canvas } = createT(THREE, [EventPlugin])
return <Canvas contexts={[EventPlugin.Provider]}>
...
</Canvas> |
- simplifies signature/implementation significantly - removes the question of where/who/what/when the setup should happen - instead of setup-method in plugin, if you want to do setup and context: use context. e.g. attaching a .Provider to your plugin and passing the plugin to Canvas' context-prop: <Canvas contexts={[EventPlugin]} /> -> you could also inject the provider like <Canvas><Plugin.Provider>..., but for plugins that want to modify the canvas-props, you will have to pass it to canvas' context-prop.
include @react-three/fiber's license, as we do in solid-drei
Currently i am resolving the methods for each entity to a unique object. This is extra memory overhead per entity. A solution could be to change the API and resolve the prop dynamically createEffect(() => {
for(const key of props){
// plugin.run returns true if the plugin contained the method
if(plugins.find(plugin => plugin.run(element, props, key))) return
...
}
}) If the selector is a The API of the plugin should change then, to something like: const Plugin = plugin([Mesh],
{
onMouseDown(element, value){
...
}
}
)
// or
const Plugin = plugin([Mesh],
(element, key, value) => {
...
}
) |
goodbye .claude 👋
Initial implementation of a plugin-system, continuing on #32
Plugin API
Vibe coded with
claude
on the plugin API choices. It's a bit much with the overloads, but it feels fun to use and the api allows for nice type inference.Usage
via createT
via prop
Event Plugin
Abstracted the event handling that we inherited from
react-three-fiber
out of core and into a plugin:EventPlugin