Skip to content

Commit 8d0377e

Browse files
committed
docs: simplify useLoader and Resource section
1 parent b04d2f5 commit 8d0377e

1 file changed

Lines changed: 47 additions & 217 deletions

File tree

README.md

Lines changed: 47 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -406,34 +406,40 @@ const App = () => {
406406

407407
### Resource
408408

409-
Declarative component for loading Three.js resources with automatic caching and Suspense integration. When no children are provided, the loaded resource is automatically rendered with any additional props passed through.
409+
Wrapper-component around ['useLoader'](#useloader).
410410

411411
**Props:**
412412

413413
- `loader` - Three.js loader constructor (e.g., `TextureLoader`, `GLTFLoader`)
414-
- `url` - URL(s) to load (string, array, or object)
414+
- `url` - URL(s) to load, depending on what the passed loader expects
415415
- `children` - Optional render function
416416
- `*` - Additional props are passed to the loaded resource
417417

418418
**Examples:**
419419

420420
```tsx
421-
// Automatic attachment with the attach prop
421+
// CubeTextureLoader expects an array of strings
422+
<Resource loader={CubeTextureLoader} url={[
423+
'px.png', 'nx.png',
424+
'py.png', 'ny.png',
425+
'pz.png', 'nz.png'
426+
]} />
427+
428+
// Set props of the resulting resource
422429
<T.MeshStandardMaterial>
423430
<Resource loader={TextureLoader} url="diffuse.jpg" attach="map" />
424431
<Resource loader={TextureLoader} url="normal.jpg" attach="normalMap" />
425432
</T.MeshStandardMaterial>
426433

427-
// Automatic model rendering with transform props
428-
<Resource loader={GLTFLoader} url="model.gltf" scale={2} position={[0, 1, 0]} />
429-
430434
// Custom rendering with children function
431-
<Resource loader={TextureLoader} url="texture.jpg">
432-
{texture => <T.MeshBasicMaterial map={texture()} />}
435+
<Resource loader={GLTFLoader} url="model.gltf">
436+
{
437+
(gltf) => <Entity from={gltf.scene} scale={2} />
438+
}
433439
</Resource>
434440

435441
// Disable caching for specific resources
436-
<Resource loader={TextureLoader} url="dynamic.jpg" cache={false} />
442+
<Resource loader={TextureLoader} url="/dynamic-texture.png" cache={false} />
437443
```
438444

439445
## Hooks
@@ -466,27 +472,24 @@ Provides access to the `three.js` context, including the renderer, scene, camera
466472
- **Default at Tail**: The `defaultCamera` and `defaultRaycaster` from Canvas props form the tail of their respective stacks
467473
- **Current Active Camera at Head**: The camera/raycaster at the top of the stack is the currently active camera/raycaster
468474
- **Push To The Stack To Become Active**: By calling `setCamera(camera)` and `setRaycaster(raycaster)`, the camera/raycaster is pushed to the stack. This causes it to become the currently active camera/raycaster
469-
- **Easily Pop From The Stack**: `setCamera(camera)` and `setRaycaster(raycaster)` return a function to pop the camera/raycaster from the stack. If the camera/raycaster was on top of the stack, the previous camera/raycaster in the stack becomes active again
475+
- **Pop From The Stack To Deactivate**: `setCamera(camera)` and `setRaycaster(raycaster)` return a cleanup-function to pop the camera/raycaster from the stack. If the camera/raycaster was on top of the stack, the previous camera/raycaster in the stack becomes active again
470476

471477
**Usage:**
472478

473479
```tsx
474-
const three = useThree()
475-
476-
// Push a new camera onto the stack
477-
const restoreCamera = three.setCamera(myCustomCamera)
480+
function Camera(props) {
481+
const three = useThree()
482+
const customCamera = new OrthographicCamera(/* ... */)
478483

479-
// The custom camera is now active
480-
// When done, call the cleanup to restore previous camera
481-
restoreCamera()
484+
// Push a new camera onto the stack
485+
const restoreCamera = three.setCamera(customCamera)
482486

483-
// Example with automatic cleanup
484-
createEffect(() => {
485-
const customCamera = new OrthographicCamera(/* ... */)
486-
const restore = three.setCamera(customCamera)
487+
// The custom camera is now active
488+
// When done, call the cleanup to pop camera from the stack
489+
onCleanup(restoreCamera)
487490

488-
onCleanup(restore) // Automatically restore previous camera when effect re-runs or unmounts
489-
})
491+
return null!
492+
}
490493
```
491494

492495
**Practical Example - Camera Switching:**
@@ -593,39 +596,14 @@ const AnimatedMesh = () => {
593596

594597
Manages asynchronous resource loading, such as textures or models, and integrates with `solid-js`' reactivity system. This hook can be used with Solid's `<Suspense>` to handle loading states.
595598

596-
**Caching Behavior:**
597-
598-
By default, `useLoader` automatically caches resources using the built-in [`LoaderCache`](#loadercache) implementation. This means:
599-
600-
- Resources are only loaded once and shared across components
601-
- Automatic reference counting tracks resource usage
602-
- Resources are added to a freelist when not referenced
603-
- Each loader type maintains its own isolated namespace
599+
By default, `useLoader` automatically caches resources via [`LoaderCache`](#loadercache).
604600

605601
You can customize caching behavior:
606602

607603
1. **Disable caching**: Pass `cache: false` in options for specific resources
608604
2. **Custom cache**: Pass your own `LoaderRegistry` implementation in options
609605
3. **Replace global cache**: Set `useLoader.cache` to your own implementation or `undefined` to disable
610606

611-
**Usage:**
612-
613-
```tsx
614-
// Load a single resource
615-
const texture = useLoader(TextureLoader, url)
616-
const gltf = useLoader(GLTFLoader, "model.gltf")
617-
618-
// Load multiple resources (with object keys)
619-
const textures = useLoader(TextureLoader, {
620-
diffuse: "wood-diffuse.jpg",
621-
normal: "wood-normal.jpg",
622-
})
623-
624-
// Reactive URLs (can be signals or getters)
625-
const [url, setUrl] = createSignal("texture.jpg")
626-
const texture = useLoader(TextureLoader, url)
627-
```
628-
629607
**Options:**
630608

631609
- **base**: Base URL for resolving relative paths
@@ -647,91 +625,27 @@ interface UseLoaderOptions<TLoader, TResult> {
647625

648626
</details>
649627

650-
#### Single Resource Loading
628+
#### Example
651629

652630
```tsx
653-
import { createSignal, Suspense } from "solid-js"
654-
import { Canvas, useLoader, createT } from "solid-three"
655-
import { TextureLoader } from "three"
656-
import * as THREE from "three"
657-
658-
const T = createT({
659-
Mesh: THREE.Mesh,
660-
SphereGeometry: THREE.SphereGeometry,
661-
MeshBasicMaterial: THREE.MeshBasicMaterial,
662-
})
663-
664-
const TexturedSphere = () => {
665-
const [url, setUrl] = createSignal("path/to/texture.jpg")
666-
const texture = useLoader(TextureLoader, url)
667-
668-
return (
669-
<T.Mesh onClick={() => setUrl("path/to/other/texture.jpg")}>
670-
<T.SphereGeometry args={[1, 32, 32]} />
671-
<T.MeshBasicMaterial map={texture()} />
672-
</T.Mesh>
673-
)
674-
}
675-
676-
const App = () => {
677-
return (
678-
<Canvas>
679-
<Suspense fallback={<div>Loading...</div>}>
680-
<TexturedSphere />
681-
</Suspense>
682-
</Canvas>
683-
)
684-
}
685-
```
686-
687-
#### Multiple Resource Loading
688-
689-
```tsx
690-
import { For, Suspense } from "solid-js"
691-
import { Canvas, useLoader, createT } from "solid-three"
692-
import { TextureLoader } from "three"
693-
import * as THREE from "three"
631+
// Load a single resource
632+
const texture = useLoader(TextureLoader, url)
633+
const gltf = useLoader(GLTFLoader, "model.gltf")
694634

695-
const T = createT({
696-
Mesh: THREE.Mesh,
697-
PlaneGeometry: THREE.PlaneGeometry,
698-
MeshBasicMaterial: THREE.MeshBasicMaterial,
635+
// Load multiple resources (with object keys)
636+
const textures = useLoader(TextureLoader, {
637+
diffuse: "wood-diffuse.jpg",
638+
normal: "wood-normal.jpg",
699639
})
700640

701-
const TexturedPlanes = () => {
702-
const textures = useLoader(TextureLoader, {
703-
wood: "/textures/wood.jpg",
704-
metal: "/textures/metal.jpg",
705-
})
706-
707-
return (
708-
<>
709-
<T.Mesh position={[0, 0, 0]}>
710-
<T.PlaneGeometry args={[2, 2]} />
711-
<T.MeshBasicMaterial map={textures()?.wood} />
712-
</T.Mesh>
713-
<T.Mesh position={[0, 0, 0]}>
714-
<T.PlaneGeometry args={[2, 2]} />
715-
<T.MeshBasicMaterial map={textures()?.metal} />
716-
</T.Mesh>
717-
</>
718-
)
719-
}
720-
721-
const App = () => {
722-
return (
723-
<Canvas>
724-
<Suspense>
725-
<TexturedPlanes />
726-
</Suspense>
727-
</Canvas>
728-
)
729-
}
641+
// Reactive URLs (can be signals or getters)
642+
const [url, setUrl] = createSignal("texture.jpg")
643+
const texture = useLoader(TextureLoader, url)
730644
```
731645

732-
#### Caching
646+
#### Custom Cache
733647

734-
`solid-three` provides the `LoaderCache` class for caching, but you can also implement your own cache by conforming to the `LoaderRegistry` interface.
648+
`solid-three` by default caches useLoader via `LoaderCache`, but you can also implement your own cache by conforming to the `LoaderRegistry` interface.
735649

736650
A cache registry needs two methods:
737651

@@ -743,106 +657,22 @@ A cache registry needs two methods:
743657

744658
```tsx
745659
interface LoaderRegistry {
746-
set<TData extends object, TUrl extends string | string[]>(
747-
loader: Loader<TData, TUrl>,
748-
url: TUrl,
749-
data: Promise<TData>,
660+
set<TLoader extends Loader<object, any>>(
661+
loader: TLoader,
662+
url: LoaderUrl<TLoader>,
663+
data: PromiseMaybe<LoaderData<TLoader>>,
750664
): void
751665

752-
get<TData extends object, TUrl extends string | string[]>(
666+
get<TLoader extends Loader<object, any>>(
753667
loader: Loader<TData, TUrl>,
754-
url: TUrl,
668+
url: LoaderUrl<TLoader>,
755669
warn?: boolean,
756-
): Promise<TData> | TData | undefined
670+
): PromiseMaybe<LoaderData<TLoader>> | undefined
757671
}
758672
```
759673

760674
</details>
761675

762-
**Working with the Default Cache:**
763-
764-
`useLoader` comes with caching enabled by default using `LoaderCache`:
765-
766-
```tsx
767-
import { useLoader } from "solid-three"
768-
769-
// Resources are automatically cached
770-
const texture1 = useLoader(TextureLoader, "texture1.jpg") // Loaded and cached
771-
const texture2 = useLoader(TextureLoader, "texture1.jpg") // Returns cached version
772-
773-
// Disable caching for specific resources
774-
const texture3 = useLoader(TextureLoader, "texture2.jpg", {
775-
cache: false, // This resource won't be cached
776-
})
777-
778-
// Use a different cache for specific calls
779-
import { LoaderCache } from "solid-three"
780-
781-
const customCache = new LoaderCache()
782-
const texture4 = useLoader(TextureLoader, "texture3.jpg", {
783-
cache: customCache, // Uses custom cache instead of global
784-
})
785-
786-
// Replace or disable the global cache
787-
useLoader.cache = new LoaderCache() // Replace with new instance
788-
useLoader.cache = undefined // Disable global caching entirely
789-
```
790-
791-
**Creating a simple custom cache:**
792-
793-
```tsx
794-
import type { LoaderRegistry } from "solid-three"
795-
import type { Loader } from "three"
796-
797-
class SimpleCache implements LoaderRegistry {
798-
private cache = new Map<Loader<any, any>, Map<string, any>>()
799-
800-
set(loader: Loader<any, any>, url: string | string[], data: Promise<any>) {
801-
let loaderCache = this.cache.get(loader)
802-
if (!loaderCache) {
803-
loaderCache = new Map()
804-
this.cache.set(loader, loaderCache)
805-
}
806-
const key = Array.isArray(url) ? url.join(",") : url
807-
loaderCache.set(key, data)
808-
}
809-
810-
get(loader: Loader<any, any>, url: string | string[]) {
811-
const loaderCache = this.cache.get(loader)
812-
if (!loaderCache) return undefined
813-
814-
const key = Array.isArray(url) ? url.join(",") : url
815-
return loaderCache.get(key)
816-
}
817-
}
818-
819-
// Use your custom cache
820-
const myCache = new SimpleCache()
821-
useLoader.cache = myCache
822-
823-
// Or per-call
824-
const texture = useLoader(TextureLoader, url, { cache: myCache })
825-
```
826-
827-
**Advanced Usage with Multiple Loaders:**
828-
829-
```tsx
830-
import { useLoader } from "solid-three"
831-
import { TextureLoader, GLTFLoader, AudioLoader } from "three"
832-
833-
// The default LoaderCache handles multiple loader types automatically
834-
const App = () => {
835-
// These all use the same cache but different namespaces
836-
const texture = useLoader(TextureLoader, "asset.jpg")
837-
const model = useLoader(GLTFLoader, "asset.gltf")
838-
const sound = useLoader(AudioLoader, "asset.mp3")
839-
840-
// Same path but different loader = different resource
841-
const textureAsset = useLoader(TextureLoader, "shared-name")
842-
const modelAsset = useLoader(GLTFLoader, "shared-name") // Different resource
843-
}
844-
```
845-
846676
### useProps
847677

848678
The `useProps` hook manages and applies `solid-three` props to THREE.js objects. It sets up reactive effects to ensure properties are correctly applied and updated, manages children attachment, and handles automatic disposal.

0 commit comments

Comments
 (0)