Skip to content

Commit 99f8ddc

Browse files
committed
cleanup: cleanup EventPlugin, remove Canvas-export
1 parent f740cb2 commit 99f8ddc

File tree

14 files changed

+285
-592
lines changed

14 files changed

+285
-592
lines changed

playground/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { A, Route, Router } from "@solidjs/router"
22
import type { ParentProps } from "solid-js"
33
import * as THREE from "three"
4-
import { Canvas, createT, Entity } from "../src/index.ts"
4+
import { createT, Entity } from "../src/index.ts"
55
import { EnvironmentExample } from "./examples/EnvironmentExample.tsx"
66
import { PluginExample } from "./examples/PluginExample.tsx"
77
import { PortalExample } from "./examples/PortalExample.tsx"
88
import { SolarExample } from "./examples/SolarExample.tsx"
99
import "./index.css"
1010

11-
const { T } = createT({ ...THREE, Entity })
11+
const { T, Canvas } = createT({ ...THREE, Entity })
1212

1313
function Layout(props: ParentProps) {
1414
return (

src/canvas.tsx renamed to src/create-canvas.tsx

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import {
1010
} from "three"
1111
import { createThree } from "./create-three.tsx"
1212
import type { EventRaycaster } from "./raycasters.tsx"
13-
import type { CanvasEventHandlers, Context, Plugin, Props } from "./types.ts"
13+
import type { Context, Plugin, PluginPropsOf, Props } from "./types.ts"
1414

1515
/**
1616
* Props for the Canvas component, which initializes the Three.js rendering context and acts as the root for your 3D scene.
1717
*/
18-
export interface CanvasProps extends ParentProps<Partial<CanvasEventHandlers>> {
18+
export interface CanvasProps extends ParentProps {
1919
ref?: Ref<Context>
2020
class?: string
2121
/** Configuration for the camera used in the scene. */
@@ -55,64 +55,8 @@ export interface CanvasProps extends ParentProps<Partial<CanvasEventHandlers>> {
5555
* @param props - Configuration options include camera settings, style, and children elements.
5656
* @returns A div element containing the WebGL canvas configured to occupy the full available space.
5757
*/
58-
export function Canvas(props: ParentProps<CanvasProps>) {
59-
let canvas: HTMLCanvasElement = null!
60-
let container: HTMLDivElement = null!
61-
62-
onMount(() => {
63-
const context = createThree(canvas, props)
64-
65-
// Resize observer for the canvas to adjust camera and renderer on size change
66-
createResizeObserver(container, function onResize() {
67-
const { width, height } = container.getBoundingClientRect()
68-
context.gl.setSize(width, height)
69-
context.gl.setPixelRatio(globalThis.devicePixelRatio)
70-
71-
if (context.currentCamera instanceof OrthographicCamera) {
72-
context.currentCamera.left = width / -2
73-
context.currentCamera.right = width / 2
74-
context.currentCamera.top = height / 2
75-
context.currentCamera.bottom = height / -2
76-
} else {
77-
context.currentCamera.aspect = width / height
78-
}
79-
80-
context.currentCamera.updateProjectionMatrix()
81-
context.render(performance.now())
82-
})
83-
})
84-
85-
return (
86-
<div
87-
ref={container!}
88-
style={{
89-
position: "relative",
90-
width: "100%",
91-
height: "100%",
92-
overflow: "hidden",
93-
contain: "strict",
94-
display: "flex",
95-
...props.style,
96-
}}
97-
class={props.class}
98-
>
99-
<canvas ref={canvas!} />
100-
</div>
101-
)
102-
}
103-
104-
/**
105-
* Serves as the root component for all 3D scenes created with `solid-three`. It initializes
106-
* the Three.js rendering context, including a WebGL renderer, a scene, and a camera.
107-
* All `<T/>`-components must be children of this Canvas. Hooks such as `useThree` and
108-
* `useFrame` should only be used within this component to ensure proper context.
109-
*
110-
* @function Canvas
111-
* @param props - Configuration options include camera settings, style, and children elements.
112-
* @returns A div element containing the WebGL canvas configured to occupy the full available space.
113-
*/
114-
export function createCanvas<TPlugins extends Plugin[] = $3.Plugins>(plugins: TPlugins) {
115-
return function (props: ParentProps<CanvasProps>) {
58+
export function createCanvas<TPlugins extends Plugin[] = Plugin[]>(plugins: TPlugins) {
59+
return function (props: ParentProps<CanvasProps> & Partial<PluginPropsOf<Scene, TPlugins>>) {
11660
let canvas: HTMLCanvasElement = null!
11761
let container: HTMLDivElement = null!
11862

src/create-t.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createMemo, type Component, type JSX, type JSXElement, type MergeProps } from "solid-js"
2-
import { createCanvas } from "./canvas.tsx"
32
import { $S3C } from "./constants.ts"
3+
import { createCanvas } from "./create-canvas.tsx"
44
import { useProps } from "./props.ts"
55
import type { Plugin, Props } from "./types.ts"
66
import { meta } from "./utils.ts"

src/create-three.tsx

Lines changed: 108 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { ReactiveMap } from "@solid-primitives/map"
22
import {
3-
children,
43
createEffect,
54
createMemo,
65
createRenderEffect,
@@ -24,8 +23,7 @@ import {
2423
VSMShadowMap,
2524
WebGLRenderer,
2625
} from "three"
27-
import type { CanvasProps } from "./canvas.tsx"
28-
import { Stack } from "./data-structure/stack.ts"
26+
import type { CanvasProps } from "./create-canvas.tsx"
2927
import { frameContext, threeContext } from "./hooks.ts"
3028
import { pluginContext } from "./internal-context.ts"
3129
import { useProps, useSceneGraph } from "./props.ts"
@@ -38,14 +36,16 @@ import {
3836
meta,
3937
removeElementFromArray,
4038
useRef,
39+
withContext,
4140
withMultiContexts,
4241
} from "./utils.ts"
42+
import { Stack } from "./utils/stack.ts"
4343
import { useMeasure } from "./utils/use-measure.ts"
4444

4545
/**
4646
* Creates and manages a `solid-three` scene. It initializes necessary objects like
47-
* camera, renderer, raycaster, and scene, manages the scene graph, setups up an event system
48-
* and rendering loop based on the provided properties.
47+
* camera, renderer, raycaster, and scene, manages the scene graph, setups up a rendering loop
48+
* based on the provided properties.
4949
*/
5050
export function createThree(canvas: HTMLCanvasElement, props: CanvasProps, plugins: Plugin[]) {
5151
const canvasProps = defaultProps(props, { frameloop: "always" })
@@ -206,22 +206,24 @@ export function createThree(canvas: HTMLCanvasElement, props: CanvasProps, plugi
206206

207207
const raycasterStack = new Stack<Raycaster>("raycaster")
208208

209+
const glProp = createMemo(() => props.gl)
209210
const gl = createMemo(() => {
210-
const gl =
211-
props.gl instanceof WebGLRenderer
212-
? // props.gl can be a WebGLRenderer provided by the user
213-
props.gl
214-
: typeof props.gl === "function"
211+
const _glProp = glProp()
212+
return meta(
213+
_glProp instanceof WebGLRenderer
214+
? // _glProp can be a WebGLRenderer provided by the user
215+
_glProp
216+
: typeof _glProp === "function"
215217
? // or a callback that returns a Renderer
216-
props.gl(canvas)
217-
: // if props.gl is not defined we default to a WebGLRenderer
218-
new WebGLRenderer({ canvas })
219-
220-
return meta(gl, {
221-
get props() {
222-
return props.gl || {}
218+
_glProp(canvas)
219+
: // if _glProp is not defined we default to a WebGLRenderer
220+
new WebGLRenderer({ canvas }),
221+
{
222+
get props() {
223+
return glProp() || {}
224+
},
223225
},
224-
})
226+
)
225227
})
226228

227229
const measure = useMeasure()
@@ -297,92 +299,98 @@ export function createThree(canvas: HTMLCanvasElement, props: CanvasProps, plugi
297299
/* */
298300
/**********************************************************************************/
299301

300-
withMultiContexts(() => {
301-
createRenderEffect(() => {
302-
if (props.frameloop === "never") {
303-
context.clock.stop()
304-
context.clock.elapsedTime = 0
305-
} else {
306-
context.clock.start()
307-
}
308-
})
302+
withContext(
303+
() => {
304+
createRenderEffect(() => {
305+
if (props.frameloop === "never") {
306+
context.clock.stop()
307+
context.clock.elapsedTime = 0
308+
} else {
309+
context.clock.start()
310+
}
311+
})
309312

310-
// Manage camera
311-
createRenderEffect(() => {
312-
if (cameraStack.peek()) return
313-
if (!props.defaultCamera || props.defaultCamera instanceof Camera) return
314-
useProps(defaultCamera, props.defaultCamera)
315-
// NOTE: Manually update camera's matrix with updateMatrixWorld is needed.
316-
// Otherwise casting a ray immediately after start-up will cause the incorrect matrix to be used.
317-
defaultCamera().updateMatrixWorld(true)
318-
})
313+
// Manage camera
314+
createRenderEffect(() => {
315+
if (cameraStack.peek()) return
316+
if (!props.defaultCamera || props.defaultCamera instanceof Camera) return
317+
useProps(defaultCamera, props.defaultCamera)
318+
// NOTE: Manually update camera's matrix with updateMatrixWorld is needed.
319+
// Otherwise casting a ray immediately after start-up will cause the incorrect matrix to be used.
320+
defaultCamera().updateMatrixWorld(true)
321+
})
319322

320-
// Manage scene
321-
createRenderEffect(() => {
322-
if (!props.scene || props.scene instanceof Scene) return
323-
useProps(scene, props.scene)
324-
})
323+
// Manage scene
324+
createRenderEffect(() => {
325+
if (!props.scene || props.scene instanceof Scene) return
326+
useProps(scene, props.scene)
327+
})
325328

326-
// Manage raycaster
327-
createRenderEffect(() => {
328-
if (!props.defaultRaycaster || props.defaultRaycaster instanceof Raycaster) return
329-
useProps(defaultRaycaster, props.defaultRaycaster)
330-
})
329+
// Manage raycaster
330+
createRenderEffect(() => {
331+
if (!props.defaultRaycaster || props.defaultRaycaster instanceof Raycaster) return
332+
useProps(defaultRaycaster, props.defaultRaycaster)
333+
})
331334

332-
// Manage gl
333-
createRenderEffect(() => {
334-
// Set shadow-map
335+
// Manage gl
335336
createRenderEffect(() => {
336-
const _gl = gl()
337-
if (_gl.shadowMap) {
338-
const oldEnabled = _gl.shadowMap.enabled
339-
const oldType = _gl.shadowMap.type
340-
_gl.shadowMap.enabled = !!props.shadows
341-
342-
if (typeof props.shadows === "boolean") {
343-
_gl.shadowMap.type = PCFSoftShadowMap
344-
} else if (typeof props.shadows === "string") {
345-
const types = {
346-
basic: BasicShadowMap,
347-
percentage: PCFShadowMap,
348-
soft: PCFSoftShadowMap,
349-
variance: VSMShadowMap,
337+
// Set shadow-map
338+
createRenderEffect(() => {
339+
const _gl = gl()
340+
341+
if (_gl.shadowMap) {
342+
const oldEnabled = _gl.shadowMap.enabled
343+
const oldType = _gl.shadowMap.type
344+
_gl.shadowMap.enabled = !!props.shadows
345+
346+
if (typeof props.shadows === "boolean") {
347+
_gl.shadowMap.type = PCFSoftShadowMap
348+
} else if (typeof props.shadows === "string") {
349+
const types = {
350+
basic: BasicShadowMap,
351+
percentage: PCFShadowMap,
352+
soft: PCFSoftShadowMap,
353+
variance: VSMShadowMap,
354+
}
355+
_gl.shadowMap.type = types[props.shadows] ?? PCFSoftShadowMap
356+
} else if (typeof props.shadows === "object") {
357+
Object.assign(_gl.shadowMap, props.shadows)
350358
}
351-
_gl.shadowMap.type = types[props.shadows] ?? PCFSoftShadowMap
352-
} else if (typeof props.shadows === "object") {
353-
Object.assign(_gl.shadowMap, props.shadows)
359+
360+
if (oldEnabled !== _gl.shadowMap.enabled || oldType !== _gl.shadowMap.type)
361+
_gl.shadowMap.needsUpdate = true
354362
}
363+
})
355364

356-
if (oldEnabled !== _gl.shadowMap.enabled || oldType !== _gl.shadowMap.type)
357-
_gl.shadowMap.needsUpdate = true
358-
}
359-
})
365+
createEffect(() => {
366+
const renderer = gl()
367+
// Connect to xr if property exists
368+
if (renderer.xr) context.xr.connect()
369+
})
360370

361-
createEffect(() => {
362-
const renderer = gl()
363-
// Connect to xr if property exists
364-
if (renderer.xr) context.xr.connect()
365-
})
371+
// Set color space and tonemapping preferences
372+
const LinearEncoding = 3000
373+
const sRGBEncoding = 3001
374+
// Color management and tone-mapping
375+
useProps(gl, {
376+
get outputEncoding() {
377+
return props.linear ? LinearEncoding : sRGBEncoding
378+
},
379+
get toneMapping() {
380+
return props.flat ? NoToneMapping : ACESFilmicToneMapping
381+
},
382+
})
366383

367-
// Set color space and tonemapping preferences
368-
const LinearEncoding = 3000
369-
const sRGBEncoding = 3001
370-
// Color management and tone-mapping
371-
useProps(gl, {
372-
get outputEncoding() {
373-
return props.linear ? LinearEncoding : sRGBEncoding
374-
},
375-
get toneMapping() {
376-
return props.flat ? NoToneMapping : ACESFilmicToneMapping
377-
},
384+
// Manage props
385+
const _glProp = glProp()
386+
if (_glProp && !(_glProp instanceof WebGLRenderer)) {
387+
useProps(gl, _glProp)
388+
}
378389
})
379-
380-
// Manage props
381-
if (props.gl && !(props.gl instanceof WebGLRenderer)) {
382-
useProps(gl, props.gl)
383-
}
384-
})
385-
}, [[threeContext, context]])
390+
},
391+
threeContext,
392+
context,
393+
)
386394

387395
/**********************************************************************************/
388396
/* */
@@ -408,20 +416,16 @@ export function createThree(canvas: HTMLCanvasElement, props: CanvasProps, plugi
408416
/* */
409417
/**********************************************************************************/
410418

411-
const c = children(() => (
412-
<pluginContext.Provider value={plugins}>
413-
<frameContext.Provider value={addFrameListener}>
414-
<threeContext.Provider value={context}>{canvasProps.children}</threeContext.Provider>
415-
</frameContext.Provider>
416-
</pluginContext.Provider>
417-
))
418-
419419
useSceneGraph(
420420
context.scene,
421421
mergeProps(props, {
422-
get children() {
423-
return c()
424-
},
422+
children: (
423+
<pluginContext.Provider value={plugins}>
424+
<frameContext.Provider value={addFrameListener}>
425+
<threeContext.Provider value={context}>{canvasProps.children}</threeContext.Provider>
426+
</frameContext.Provider>
427+
</pluginContext.Provider>
428+
),
425429
}),
426430
)
427431

0 commit comments

Comments
 (0)