core

A separate file is useful when it isolates behavior or protects a dependency boundary. It does not necessarily introduce another domain. A boundary should reduce what a maintainer must understand to change that behavior, with tests covering its observable contract.

AreaImplementationContract and coverage
Root managementroot.tsx, configuration.ts, store.tsRoot sequences accepted work and teardown. Configuration applies changed inputs and follows device pixel ratio. Store owns runtime state and resize effects. index, configuration, and dpr tests cover readiness, cancelled unmounts, input diffing, and imperative updates.
Reconciliationreconciler.tsx, extend.ts, portal.tsxConstructor registration and lookup, scene mutations, and portal state inheritance. renderer and types tests cover construction, attachments, disposal, portal isolation, and Activity visibility.
Renderer resourcesrenderer.tsCreate a renderer from defaults, props, an instance, or a factory. Release resources according to ownership after React cleanup. renderer and index tests cover owned and caller-provided renderers, late initialization, asynchronous disposal, and cleanup failures.
Frame schedulingloop.ts, hooks.tsxSchedule frames, subscriptions, and global effects. hooks and renderer tests cover frame modes, invalidation, priority, and render takeover.
Interactionevents.tsRaycasting, event propagation, hover, and pointer capture. events tests cover public handlers, bubbling, capture, and removal.
Platform adaptersweb/Canvas.tsx, web/events.ts, native/Canvas.tsx, native/events.tsAdapt DOM or native measurements and events to the root API. Web and native Canvas tests cover mounting, context, refs, Suspense, Activity, and cleanup.

The root publishes tracked readiness before accepting more configuration. Synchronous renderer creation stays synchronous. Async factories delay configuration and rendering until their renderer is ready. A cancelled unmount keeps the root, while final teardown waits for accepted configuration and React effect cleanup before releasing renderer resources.

Configuration owns declarative inputs. Equal inputs preserve runtime edits, including camera, frame mode, and renderer settings. The store applies size and pixel ratio changes to the camera and renderer.

Renderer ownership belongs to root lifetime. R3F disposes renderers it creates, including factory results. For caller-provided instances, v9 releases render lists and loses the context without disposing the renderer. An async disposal finishes before the unmount callback runs.

Activity connectivity does not own renderer lifetime. Hiding disconnects scene effects and frame subscriptions while preserving scene state and the renderer. Final removal releases the root, including removal while hidden. Suspense gates renderer readiness and scene loading separately, so waiting does not dispose a live renderer.

Promise helpers in core/utils/promise.ts and React helpers in core/utils/react.tsx are infrastructure. They support these contracts rather than forming separate application domains. core/utils.tsx retains the shared scene utilities and compatibility exports. JSX types in three-types.ts describe the public element surface.