@react-three/fiber 10.0.0-canary.c3fa45d → 10.0.0-canary.d6fdf72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +77 -97
- package/dist/index.d.cts +81 -54
- package/dist/index.d.mts +81 -54
- package/dist/index.d.ts +81 -54
- package/dist/index.mjs +77 -97
- package/dist/legacy.cjs +77 -97
- package/dist/legacy.d.cts +81 -54
- package/dist/legacy.d.mts +81 -54
- package/dist/legacy.d.ts +81 -54
- package/dist/legacy.mjs +77 -97
- package/dist/webgpu/index.cjs +77 -97
- package/dist/webgpu/index.d.cts +81 -54
- package/dist/webgpu/index.d.mts +81 -54
- package/dist/webgpu/index.d.ts +81 -54
- package/dist/webgpu/index.mjs +77 -97
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2821,6 +2821,7 @@ const createStore = (invalidate, advance) => {
|
|
|
2821
2821
|
buffers: {},
|
|
2822
2822
|
gpuStorage: {},
|
|
2823
2823
|
textures: /* @__PURE__ */ new Map(),
|
|
2824
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
2824
2825
|
renderPipeline: null,
|
|
2825
2826
|
passes: {},
|
|
2826
2827
|
_hmrVersion: 0,
|
|
@@ -3184,18 +3185,18 @@ function buildFromCache(input, textureCache) {
|
|
|
3184
3185
|
function useTexture(input, optionsOrOnLoad) {
|
|
3185
3186
|
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
3186
3187
|
const store = useStore();
|
|
3187
|
-
const textureCache = useThree((state) => state.textures);
|
|
3188
3188
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
3189
|
-
const { onLoad, cache =
|
|
3189
|
+
const { onLoad, cache = true } = options;
|
|
3190
3190
|
const onLoadRef = React.useRef(onLoad);
|
|
3191
3191
|
onLoadRef.current = onLoad;
|
|
3192
3192
|
const onLoadCalledForRef = React.useRef(null);
|
|
3193
3193
|
const urls = React.useMemo(() => getUrls(input), [input]);
|
|
3194
3194
|
const cachedResult = React.useMemo(() => {
|
|
3195
3195
|
if (!cache) return null;
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3196
|
+
const textures = store.getState().textures;
|
|
3197
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
3198
|
+
return buildFromCache(input, textures);
|
|
3199
|
+
}, [cache, urls, input, store]);
|
|
3199
3200
|
const loadedTextures = useLoader(
|
|
3200
3201
|
webgpu.TextureLoader,
|
|
3201
3202
|
IsObject(input) ? Object.values(input) : input
|
|
@@ -3239,8 +3240,6 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3239
3240
|
}, [input, loadedTextures, cachedResult]);
|
|
3240
3241
|
React.useEffect(() => {
|
|
3241
3242
|
if (!cache) return;
|
|
3242
|
-
if (cachedResult) return;
|
|
3243
|
-
const set = store.setState;
|
|
3244
3243
|
const urlTextureMap = [];
|
|
3245
3244
|
if (typeof input === "string") {
|
|
3246
3245
|
urlTextureMap.push([input, mappedTextures]);
|
|
@@ -3254,18 +3253,32 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3254
3253
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
3255
3254
|
}
|
|
3256
3255
|
}
|
|
3257
|
-
|
|
3258
|
-
const
|
|
3259
|
-
let
|
|
3256
|
+
store.setState((state) => {
|
|
3257
|
+
const refs = new Map(state._textureRefs);
|
|
3258
|
+
let textures = state.textures;
|
|
3259
|
+
let added = false;
|
|
3260
3260
|
for (const [url, texture] of urlTextureMap) {
|
|
3261
|
-
if (!
|
|
3262
|
-
|
|
3263
|
-
|
|
3261
|
+
if (!textures.has(url)) {
|
|
3262
|
+
if (!added) {
|
|
3263
|
+
textures = new Map(textures);
|
|
3264
|
+
added = true;
|
|
3265
|
+
}
|
|
3266
|
+
textures.set(url, texture);
|
|
3264
3267
|
}
|
|
3268
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
3265
3269
|
}
|
|
3266
|
-
return
|
|
3270
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
3267
3271
|
});
|
|
3268
|
-
|
|
3272
|
+
return () => store.setState((state) => {
|
|
3273
|
+
const refs = new Map(state._textureRefs);
|
|
3274
|
+
for (const [url] of urlTextureMap) {
|
|
3275
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
3276
|
+
if (next <= 0) refs.delete(url);
|
|
3277
|
+
else refs.set(url, next);
|
|
3278
|
+
}
|
|
3279
|
+
return { _textureRefs: refs };
|
|
3280
|
+
});
|
|
3281
|
+
}, [cache, input, mappedTextures, store]);
|
|
3269
3282
|
return mappedTextures;
|
|
3270
3283
|
}
|
|
3271
3284
|
useTexture.preload = (url) => useLoader.preload(webgpu.TextureLoader, url);
|
|
@@ -3281,96 +3294,63 @@ const Texture = ({
|
|
|
3281
3294
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
|
|
3282
3295
|
};
|
|
3283
3296
|
|
|
3284
|
-
function
|
|
3285
|
-
if (entry instanceof webgpu.Texture) return entry;
|
|
3286
|
-
if (entry && typeof entry === "object" && "value" in entry && entry.value instanceof webgpu.Texture) {
|
|
3287
|
-
return entry.value;
|
|
3288
|
-
}
|
|
3289
|
-
return null;
|
|
3290
|
-
}
|
|
3291
|
-
function useTextures() {
|
|
3297
|
+
function useTextures(selector) {
|
|
3292
3298
|
const store = useStore();
|
|
3293
|
-
|
|
3294
|
-
const set = store.setState;
|
|
3299
|
+
const registry = React.useMemo(() => {
|
|
3295
3300
|
const getState = store.getState;
|
|
3296
|
-
const
|
|
3297
|
-
|
|
3298
|
-
const newMap = new Map(state.textures);
|
|
3299
|
-
newMap.set(key, value);
|
|
3300
|
-
return { textures: newMap };
|
|
3301
|
-
});
|
|
3302
|
-
};
|
|
3303
|
-
const addMultiple = (items) => {
|
|
3304
|
-
set((state) => {
|
|
3305
|
-
const newMap = new Map(state.textures);
|
|
3306
|
-
const entries = items instanceof Map ? items.entries() : Object.entries(items);
|
|
3307
|
-
for (const [key, value] of entries) {
|
|
3308
|
-
newMap.set(key, value);
|
|
3309
|
-
}
|
|
3310
|
-
return { textures: newMap };
|
|
3311
|
-
});
|
|
3312
|
-
};
|
|
3313
|
-
const remove = (key) => {
|
|
3314
|
-
set((state) => {
|
|
3315
|
-
const newMap = new Map(state.textures);
|
|
3316
|
-
newMap.delete(key);
|
|
3317
|
-
return { textures: newMap };
|
|
3318
|
-
});
|
|
3319
|
-
};
|
|
3320
|
-
const removeMultiple = (keys) => {
|
|
3321
|
-
set((state) => {
|
|
3322
|
-
const newMap = new Map(state.textures);
|
|
3323
|
-
for (const key of keys) newMap.delete(key);
|
|
3324
|
-
return { textures: newMap };
|
|
3325
|
-
});
|
|
3326
|
-
};
|
|
3327
|
-
const dispose = (key) => {
|
|
3328
|
-
const entry = getState().textures.get(key);
|
|
3329
|
-
if (entry) {
|
|
3330
|
-
const tex = getTextureValue(entry);
|
|
3331
|
-
tex?.dispose();
|
|
3332
|
-
}
|
|
3333
|
-
remove(key);
|
|
3334
|
-
};
|
|
3335
|
-
const disposeMultiple = (keys) => {
|
|
3336
|
-
const textures = getState().textures;
|
|
3337
|
-
for (const key of keys) {
|
|
3338
|
-
const entry = textures.get(key);
|
|
3339
|
-
if (entry) {
|
|
3340
|
-
const tex = getTextureValue(entry);
|
|
3341
|
-
tex?.dispose();
|
|
3342
|
-
}
|
|
3343
|
-
}
|
|
3344
|
-
removeMultiple(keys);
|
|
3345
|
-
};
|
|
3346
|
-
const disposeAll = () => {
|
|
3347
|
-
const textures = getState().textures;
|
|
3348
|
-
for (const entry of textures.values()) {
|
|
3349
|
-
const tex = getTextureValue(entry);
|
|
3350
|
-
tex?.dispose();
|
|
3351
|
-
}
|
|
3352
|
-
set({ textures: /* @__PURE__ */ new Map() });
|
|
3353
|
-
};
|
|
3301
|
+
const setState = store.setState;
|
|
3302
|
+
const getOne = (key) => getState().textures.get(key);
|
|
3354
3303
|
return {
|
|
3355
|
-
|
|
3356
|
-
get textures() {
|
|
3304
|
+
get all() {
|
|
3357
3305
|
return getState().textures;
|
|
3358
3306
|
},
|
|
3359
|
-
|
|
3360
|
-
|
|
3307
|
+
get(input) {
|
|
3308
|
+
if (typeof input === "string") return getOne(input);
|
|
3309
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
3310
|
+
const out = {};
|
|
3311
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
3312
|
+
return out;
|
|
3313
|
+
},
|
|
3361
3314
|
has: (key) => getState().textures.has(key),
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3315
|
+
add(keyOrRecord, texture) {
|
|
3316
|
+
setState((state) => {
|
|
3317
|
+
const textures = new Map(state.textures);
|
|
3318
|
+
if (typeof keyOrRecord === "string") {
|
|
3319
|
+
textures.set(keyOrRecord, texture);
|
|
3320
|
+
} else {
|
|
3321
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
3322
|
+
}
|
|
3323
|
+
return { textures };
|
|
3324
|
+
});
|
|
3325
|
+
},
|
|
3326
|
+
dispose(key, options) {
|
|
3327
|
+
const state = getState();
|
|
3328
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
3329
|
+
if (refs > 0 && !options?.force) {
|
|
3330
|
+
console.warn(
|
|
3331
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
3332
|
+
);
|
|
3333
|
+
return false;
|
|
3334
|
+
}
|
|
3335
|
+
state.textures.get(key)?.dispose();
|
|
3336
|
+
setState((s) => {
|
|
3337
|
+
const textures = new Map(s.textures);
|
|
3338
|
+
textures.delete(key);
|
|
3339
|
+
const nextRefs = new Map(s._textureRefs);
|
|
3340
|
+
nextRefs.delete(key);
|
|
3341
|
+
return { textures, _textureRefs: nextRefs };
|
|
3342
|
+
});
|
|
3343
|
+
return true;
|
|
3344
|
+
},
|
|
3345
|
+
disposeAll() {
|
|
3346
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
3347
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
3348
|
+
}
|
|
3372
3349
|
};
|
|
3373
3350
|
}, [store]);
|
|
3351
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
3352
|
+
const selected = useThree(subscribe);
|
|
3353
|
+
return selector ? selected : registry;
|
|
3374
3354
|
}
|
|
3375
3355
|
|
|
3376
3356
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
package/dist/index.d.cts
CHANGED
|
@@ -801,8 +801,10 @@ interface RootState {
|
|
|
801
801
|
buffers: BufferStore
|
|
802
802
|
/** Global GPU storage (textures, etc.) - root-level storage + scoped sub-objects. Use useGPUStorage() hook */
|
|
803
803
|
gpuStorage: StorageStore
|
|
804
|
-
/** Global
|
|
805
|
-
textures: Map<string,
|
|
804
|
+
/** Global Texture registry (key → Texture, usually keyed by URL) - use useTextures() hook for access + lifecycle */
|
|
805
|
+
textures: Map<string, THREE$1.Texture>
|
|
806
|
+
/** Internal: refcount per texture key, driven by mounted useTexture consumers (registry enrollment is on by default) */
|
|
807
|
+
_textureRefs: Map<string, number>
|
|
806
808
|
/** WebGPU RenderPipeline instance - use useRenderPipeline() hook */
|
|
807
809
|
renderPipeline: any | null // THREE.PostProcessing (will be THREE.RenderPipeline in future Three.js release)
|
|
808
810
|
/** Global TSL pass nodes for render pipeline - use useRenderPipeline() hook */
|
|
@@ -2573,11 +2575,16 @@ type UseTextureOptions<Url extends string[] | string | Record<string, string>> =
|
|
|
2573
2575
|
/** Callback when texture(s) finish loading */
|
|
2574
2576
|
onLoad?: (texture: MappedTextureType<Url>) => void;
|
|
2575
2577
|
/**
|
|
2576
|
-
*
|
|
2577
|
-
* When true:
|
|
2578
|
+
* Register the texture(s) in R3F's global texture registry for access via useTextures().
|
|
2579
|
+
* When true (the default):
|
|
2578
2580
|
* - Textures persist until explicitly disposed
|
|
2579
|
-
* -
|
|
2580
|
-
*
|
|
2581
|
+
* - On mount, returns existing registered textures if available (preserving modifications like colorSpace)
|
|
2582
|
+
*
|
|
2583
|
+
* Reads are taken once at mount — a mounted `useTexture` does not re-render when the registry
|
|
2584
|
+
* changes. To react to registry swaps, use `useTextures(s => s.get(key))` instead.
|
|
2585
|
+
*
|
|
2586
|
+
* Pass `false` to opt out of registry enrollment entirely.
|
|
2587
|
+
* @default true
|
|
2581
2588
|
*/
|
|
2582
2589
|
cache?: boolean;
|
|
2583
2590
|
};
|
|
@@ -2601,15 +2608,18 @@ type UseTextureOptions<Url extends string[] | string | Record<string, string>> =
|
|
|
2601
2608
|
* normal: '/normal.png'
|
|
2602
2609
|
* })
|
|
2603
2610
|
*
|
|
2604
|
-
* //
|
|
2605
|
-
* //
|
|
2606
|
-
* const diffuse = useTexture('/diffuse.png'
|
|
2611
|
+
* // Textures are registered in the global registry by default — the same texture
|
|
2612
|
+
* // object is shared across components and modifications (colorSpace, wrapS, etc.) are preserved
|
|
2613
|
+
* const diffuse = useTexture('/diffuse.png')
|
|
2607
2614
|
* diffuse.colorSpace = THREE.SRGBColorSpace
|
|
2608
2615
|
*
|
|
2609
2616
|
* // Another component gets the SAME texture with colorSpace already set
|
|
2610
|
-
* const sameDiffuse = useTexture('/diffuse.png'
|
|
2617
|
+
* const sameDiffuse = useTexture('/diffuse.png')
|
|
2611
2618
|
*
|
|
2612
|
-
* //
|
|
2619
|
+
* // Opt out of registry enrollment for a one-off texture
|
|
2620
|
+
* const scratch = useTexture('/scratch.png', { cache: false })
|
|
2621
|
+
*
|
|
2622
|
+
* // Access the registry directly
|
|
2613
2623
|
* const { get } = useTextures()
|
|
2614
2624
|
* const cached = get('/diffuse.png')
|
|
2615
2625
|
* ```
|
|
@@ -2626,63 +2636,80 @@ declare const Texture: ({ children, input, onLoad, cache, }: {
|
|
|
2626
2636
|
cache?: boolean;
|
|
2627
2637
|
}) => react_jsx_runtime.JSX.Element;
|
|
2628
2638
|
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2639
|
+
/** Accepted shapes for a registry read: a single key, a list of keys, or a name→key map. */
|
|
2640
|
+
type TextureInput = string | string[] | Record<string, string>;
|
|
2641
|
+
/** Result of a `get()` read, mirroring the input shape. */
|
|
2642
|
+
type TextureResult<Input extends TextureInput> = Input extends string ? Texture$1 | undefined : Input extends string[] ? (Texture$1 | undefined)[] : {
|
|
2643
|
+
[K in keyof Input]: Texture$1 | undefined;
|
|
2632
2644
|
};
|
|
2645
|
+
/** Options for `dispose()`. */
|
|
2646
|
+
interface DisposeOptions {
|
|
2647
|
+
/** Dispose even if the texture still has active references (default false). */
|
|
2648
|
+
force?: boolean;
|
|
2649
|
+
}
|
|
2633
2650
|
interface UseTexturesReturn {
|
|
2634
|
-
/** Map
|
|
2635
|
-
|
|
2636
|
-
/**
|
|
2637
|
-
get
|
|
2638
|
-
/** Check
|
|
2639
|
-
has
|
|
2640
|
-
/**
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2651
|
+
/** The live registry Map (key → Texture). Treat as read-only. */
|
|
2652
|
+
readonly all: Map<string, Texture$1>;
|
|
2653
|
+
/** Read one texture, an array of textures, or a name→texture record (mirrors the input shape). */
|
|
2654
|
+
get<Input extends TextureInput>(input: Input): TextureResult<Input>;
|
|
2655
|
+
/** Check whether a key exists in the registry. */
|
|
2656
|
+
has(key: string): boolean;
|
|
2657
|
+
/**
|
|
2658
|
+
* Register a texture (or a record of textures) that has no URL — e.g. a render
|
|
2659
|
+
* target or procedural texture. URL-loaded textures are registered automatically
|
|
2660
|
+
* by `useTexture` (registry enrollment is on by default).
|
|
2661
|
+
*/
|
|
2662
|
+
add(key: string, texture: Texture$1): void;
|
|
2663
|
+
add(record: Record<string, Texture$1>): void;
|
|
2664
|
+
/**
|
|
2665
|
+
* Dispose a texture's GPU resources and remove it from the registry.
|
|
2666
|
+
* Refcount-aware: if the key is still in use by a mounted `useTexture` consumer it is
|
|
2667
|
+
* skipped (with a warning) unless `{ force: true }` is passed.
|
|
2668
|
+
* @returns true if disposed, false if skipped.
|
|
2669
|
+
*/
|
|
2670
|
+
dispose(key: string, options?: DisposeOptions): boolean;
|
|
2671
|
+
/** Dispose every texture in the registry and clear it. Use on scene teardown. */
|
|
2672
|
+
disposeAll(): void;
|
|
2654
2673
|
}
|
|
2655
2674
|
/**
|
|
2656
|
-
*
|
|
2675
|
+
* Reactive Texture registry — load once with `useTexture`, reach the textures from anywhere.
|
|
2676
|
+
*
|
|
2677
|
+
* This is a registry of plain `Texture` objects (not TSL nodes), so the same texture can feed
|
|
2678
|
+
* a material map, a heightmap sampler, or anything else. It does **not** load — pair it with
|
|
2679
|
+
* `useTexture` for loading (registry enrollment is on by default); `useTextures` is for access and lifecycle.
|
|
2657
2680
|
*
|
|
2658
|
-
*
|
|
2659
|
-
*
|
|
2681
|
+
* The returned handle is **reactive**: the calling component re-renders when the registry
|
|
2682
|
+
* changes. Pass a selector to scope the subscription to a single read.
|
|
2660
2683
|
*
|
|
2661
2684
|
* @example
|
|
2662
2685
|
* ```tsx
|
|
2663
|
-
*
|
|
2664
|
-
*
|
|
2665
|
-
* // Check if texture is already cached
|
|
2666
|
-
* if (!has('/textures/diffuse.png')) {
|
|
2667
|
-
* // Load with useTexture and cache: true, or manually add
|
|
2668
|
-
* const tex = useTexture('/textures/diffuse.png', { cache: true })
|
|
2669
|
-
* }
|
|
2686
|
+
* // Load + register once (anywhere in the tree) — registered by default
|
|
2687
|
+
* useTexture({ map: '/diffuse.jpg', normalMap: '/normal.jpg' })
|
|
2670
2688
|
*
|
|
2671
|
-
* //
|
|
2672
|
-
* const
|
|
2673
|
-
*
|
|
2689
|
+
* // Reach them from another component — record form lands straight into a material
|
|
2690
|
+
* const { map, normalMap } = useTextures().get({ map: '/diffuse.jpg', normalMap: '/normal.jpg' })
|
|
2691
|
+
* return <meshStandardMaterial map={map} normalMap={normalMap} />
|
|
2674
2692
|
*
|
|
2675
|
-
* //
|
|
2676
|
-
*
|
|
2693
|
+
* // A set of heightmaps at once
|
|
2694
|
+
* const [a, b, c] = useTextures().get(['/h0.png', '/h1.png', '/h2.png'])
|
|
2677
2695
|
*
|
|
2678
|
-
* //
|
|
2679
|
-
*
|
|
2696
|
+
* // Register a non-URL texture (render target / procedural)
|
|
2697
|
+
* useTextures().add('rt-main', renderTarget.texture)
|
|
2680
2698
|
*
|
|
2681
|
-
* //
|
|
2682
|
-
*
|
|
2699
|
+
* // Deliberate GPU cleanup (refcount-aware; force to override)
|
|
2700
|
+
* useTextures().dispose('/diffuse.jpg')
|
|
2701
|
+
* useTextures().disposeAll() // scene teardown
|
|
2683
2702
|
* ```
|
|
2703
|
+
*
|
|
2704
|
+
* @remarks
|
|
2705
|
+
* **Future expansion:** an imperative async loader (e.g. `await useTextures().load('/x.jpg')`) is
|
|
2706
|
+
* intentionally not included yet. It would let non-React code (loading screens, dynamic streaming)
|
|
2707
|
+
* populate the registry without Suspense, at the cost of putting loading back into this hook. It
|
|
2708
|
+
* will be added only if a concrete consumer needs imperative loading; for now, loading lives in
|
|
2709
|
+
* `useTexture`.
|
|
2684
2710
|
*/
|
|
2685
2711
|
declare function useTextures(): UseTexturesReturn;
|
|
2712
|
+
declare function useTextures<T>(selector: (registry: UseTexturesReturn) => T): T;
|
|
2686
2713
|
|
|
2687
2714
|
/**
|
|
2688
2715
|
* Creates a render target compatible with the current renderer.
|
|
@@ -4379,4 +4406,4 @@ declare function isOnce(value: unknown): value is {
|
|
|
4379
4406
|
declare function Canvas(props: CanvasProps): react_jsx_runtime.JSX.Element;
|
|
4380
4407
|
|
|
4381
4408
|
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, three_d as ReactThreeFiber, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, context, createEvents, createPointerEvents, createPortal, createRoot, createStore, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, reconciler, registerPrimary, removeInteractivity, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useMutableCallback, useRenderTarget, useStore, useTexture, useTextures, useThree, waitForPrimary };
|
|
4382
|
-
export type { Act, AddPhaseOptions, Args, ArgsProp, AttachFnType, AttachType, BackgroundConfig, BackgroundProp, BaseRendererProps, Bridge, BufferLike, BufferRecord, BufferStore, Camera, CameraProps, CanvasProps, CanvasSchedulerConfig, Catalogue, Color, ColorManagementConfig, ComputeFunction, ConstructorRepresentation, DefaultGLProps, DefaultRendererProps, Disposable, DomEvent, Dpr, ElementProps, EnvironmentLoaderProps, EnvironmentProps, EquConfig, Euler, EventHandlers, EventManager, EventProps, Events, Extensions, FiberRoot, FilterFunction, FrameCallback, FrameControls, FrameNextCallback, FrameNextControls, FrameNextState, FrameState, FrameTimingState, Frameloop, GLProps, GLTFLike, GeometryProps, GeometryTransformProps, GlobalEffectType, GlobalRenderCallback, HostConfig, InferLoadResult, InjectState, InputLike, Instance, InstanceProps, InternalState, Intersection, IntersectionEvent, IsAllOptional, IsOptional, Layers, LegacyInternalState, LegacyRenderer, LegacyRootState, LoaderInstance, LoaderLike, LoaderResult, MappedTextureType, MathProps, MathRepresentation, MathType, MathTypes, Matrix3, Matrix4, Mutable, MutableOrReadonlyParameters, NodeProps, NonFunctionKeys, ObjectMap, OffscreenCanvas$1 as OffscreenCanvas, Overwrite, Performance, PointerCaptureTarget, PointerState, PresetsType, PrimaryCanvasEntry, Properties, Quaternion, R3FRenderer, RaycastableRepresentation, ReactProps, ReconcilerRoot, RenderCallback, RenderProps, RenderTargetOptions, Renderer, RendererConfigExtended, RendererFactory, RendererProps, Root, RootOptions, RootState, RootStore, SchedulerApi, SetBlock, Size, StorageLike, StorageRecord, StorageStore, Subscription, TSLNodeInput,
|
|
4409
|
+
export type { Act, AddPhaseOptions, Args, ArgsProp, AttachFnType, AttachType, BackgroundConfig, BackgroundProp, BaseRendererProps, Bridge, BufferLike, BufferRecord, BufferStore, Camera, CameraProps, CanvasProps, CanvasSchedulerConfig, Catalogue, Color, ColorManagementConfig, ComputeFunction, ConstructorRepresentation, DefaultGLProps, DefaultRendererProps, Disposable, DisposeOptions, DomEvent, Dpr, ElementProps, EnvironmentLoaderProps, EnvironmentProps, EquConfig, Euler, EventHandlers, EventManager, EventProps, Events, Extensions, FiberRoot, FilterFunction, FrameCallback, FrameControls, FrameNextCallback, FrameNextControls, FrameNextState, FrameState, FrameTimingState, Frameloop, GLProps, GLTFLike, GeometryProps, GeometryTransformProps, GlobalEffectType, GlobalRenderCallback, HostConfig, InferLoadResult, InjectState, InputLike, Instance, InstanceProps, InternalState, Intersection, IntersectionEvent, IsAllOptional, IsOptional, Layers, LegacyInternalState, LegacyRenderer, LegacyRootState, LoaderInstance, LoaderLike, LoaderResult, MappedTextureType, MathProps, MathRepresentation, MathType, MathTypes, Matrix3, Matrix4, Mutable, MutableOrReadonlyParameters, NodeProps, NonFunctionKeys, ObjectMap, OffscreenCanvas$1 as OffscreenCanvas, Overwrite, Performance, PointerCaptureTarget, PointerState, PresetsType, PrimaryCanvasEntry, Properties, Quaternion, R3FRenderer, RaycastableRepresentation, ReactProps, ReconcilerRoot, RenderCallback, RenderProps, RenderTargetOptions, Renderer, RendererConfigExtended, RendererFactory, RendererProps, Root, RootOptions, RootState, RootStore, SchedulerApi, SetBlock, Size, StorageLike, StorageRecord, StorageStore, Subscription, TSLNodeInput, TextureInput, TextureResult, ThreeCamera, ThreeElement, ThreeElements, ThreeElementsImpl, ThreeEvent, ThreeExports, ThreeToJSXElements, UnblockProps, UseFrameNextOptions, UseFrameOptions, UseTextureOptions, UseTexturesReturn, Vector2, Vector3, Vector4, VectorRepresentation, Viewport, VisibilityEntry, WebGLDefaultProps, WebGLProps, WebGLShadowConfig, XRManager, XRPointerConfig };
|
package/dist/index.d.mts
CHANGED
|
@@ -801,8 +801,10 @@ interface RootState {
|
|
|
801
801
|
buffers: BufferStore
|
|
802
802
|
/** Global GPU storage (textures, etc.) - root-level storage + scoped sub-objects. Use useGPUStorage() hook */
|
|
803
803
|
gpuStorage: StorageStore
|
|
804
|
-
/** Global
|
|
805
|
-
textures: Map<string,
|
|
804
|
+
/** Global Texture registry (key → Texture, usually keyed by URL) - use useTextures() hook for access + lifecycle */
|
|
805
|
+
textures: Map<string, THREE$1.Texture>
|
|
806
|
+
/** Internal: refcount per texture key, driven by mounted useTexture consumers (registry enrollment is on by default) */
|
|
807
|
+
_textureRefs: Map<string, number>
|
|
806
808
|
/** WebGPU RenderPipeline instance - use useRenderPipeline() hook */
|
|
807
809
|
renderPipeline: any | null // THREE.PostProcessing (will be THREE.RenderPipeline in future Three.js release)
|
|
808
810
|
/** Global TSL pass nodes for render pipeline - use useRenderPipeline() hook */
|
|
@@ -2573,11 +2575,16 @@ type UseTextureOptions<Url extends string[] | string | Record<string, string>> =
|
|
|
2573
2575
|
/** Callback when texture(s) finish loading */
|
|
2574
2576
|
onLoad?: (texture: MappedTextureType<Url>) => void;
|
|
2575
2577
|
/**
|
|
2576
|
-
*
|
|
2577
|
-
* When true:
|
|
2578
|
+
* Register the texture(s) in R3F's global texture registry for access via useTextures().
|
|
2579
|
+
* When true (the default):
|
|
2578
2580
|
* - Textures persist until explicitly disposed
|
|
2579
|
-
* -
|
|
2580
|
-
*
|
|
2581
|
+
* - On mount, returns existing registered textures if available (preserving modifications like colorSpace)
|
|
2582
|
+
*
|
|
2583
|
+
* Reads are taken once at mount — a mounted `useTexture` does not re-render when the registry
|
|
2584
|
+
* changes. To react to registry swaps, use `useTextures(s => s.get(key))` instead.
|
|
2585
|
+
*
|
|
2586
|
+
* Pass `false` to opt out of registry enrollment entirely.
|
|
2587
|
+
* @default true
|
|
2581
2588
|
*/
|
|
2582
2589
|
cache?: boolean;
|
|
2583
2590
|
};
|
|
@@ -2601,15 +2608,18 @@ type UseTextureOptions<Url extends string[] | string | Record<string, string>> =
|
|
|
2601
2608
|
* normal: '/normal.png'
|
|
2602
2609
|
* })
|
|
2603
2610
|
*
|
|
2604
|
-
* //
|
|
2605
|
-
* //
|
|
2606
|
-
* const diffuse = useTexture('/diffuse.png'
|
|
2611
|
+
* // Textures are registered in the global registry by default — the same texture
|
|
2612
|
+
* // object is shared across components and modifications (colorSpace, wrapS, etc.) are preserved
|
|
2613
|
+
* const diffuse = useTexture('/diffuse.png')
|
|
2607
2614
|
* diffuse.colorSpace = THREE.SRGBColorSpace
|
|
2608
2615
|
*
|
|
2609
2616
|
* // Another component gets the SAME texture with colorSpace already set
|
|
2610
|
-
* const sameDiffuse = useTexture('/diffuse.png'
|
|
2617
|
+
* const sameDiffuse = useTexture('/diffuse.png')
|
|
2611
2618
|
*
|
|
2612
|
-
* //
|
|
2619
|
+
* // Opt out of registry enrollment for a one-off texture
|
|
2620
|
+
* const scratch = useTexture('/scratch.png', { cache: false })
|
|
2621
|
+
*
|
|
2622
|
+
* // Access the registry directly
|
|
2613
2623
|
* const { get } = useTextures()
|
|
2614
2624
|
* const cached = get('/diffuse.png')
|
|
2615
2625
|
* ```
|
|
@@ -2626,63 +2636,80 @@ declare const Texture: ({ children, input, onLoad, cache, }: {
|
|
|
2626
2636
|
cache?: boolean;
|
|
2627
2637
|
}) => react_jsx_runtime.JSX.Element;
|
|
2628
2638
|
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2639
|
+
/** Accepted shapes for a registry read: a single key, a list of keys, or a name→key map. */
|
|
2640
|
+
type TextureInput = string | string[] | Record<string, string>;
|
|
2641
|
+
/** Result of a `get()` read, mirroring the input shape. */
|
|
2642
|
+
type TextureResult<Input extends TextureInput> = Input extends string ? Texture$1 | undefined : Input extends string[] ? (Texture$1 | undefined)[] : {
|
|
2643
|
+
[K in keyof Input]: Texture$1 | undefined;
|
|
2632
2644
|
};
|
|
2645
|
+
/** Options for `dispose()`. */
|
|
2646
|
+
interface DisposeOptions {
|
|
2647
|
+
/** Dispose even if the texture still has active references (default false). */
|
|
2648
|
+
force?: boolean;
|
|
2649
|
+
}
|
|
2633
2650
|
interface UseTexturesReturn {
|
|
2634
|
-
/** Map
|
|
2635
|
-
|
|
2636
|
-
/**
|
|
2637
|
-
get
|
|
2638
|
-
/** Check
|
|
2639
|
-
has
|
|
2640
|
-
/**
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2651
|
+
/** The live registry Map (key → Texture). Treat as read-only. */
|
|
2652
|
+
readonly all: Map<string, Texture$1>;
|
|
2653
|
+
/** Read one texture, an array of textures, or a name→texture record (mirrors the input shape). */
|
|
2654
|
+
get<Input extends TextureInput>(input: Input): TextureResult<Input>;
|
|
2655
|
+
/** Check whether a key exists in the registry. */
|
|
2656
|
+
has(key: string): boolean;
|
|
2657
|
+
/**
|
|
2658
|
+
* Register a texture (or a record of textures) that has no URL — e.g. a render
|
|
2659
|
+
* target or procedural texture. URL-loaded textures are registered automatically
|
|
2660
|
+
* by `useTexture` (registry enrollment is on by default).
|
|
2661
|
+
*/
|
|
2662
|
+
add(key: string, texture: Texture$1): void;
|
|
2663
|
+
add(record: Record<string, Texture$1>): void;
|
|
2664
|
+
/**
|
|
2665
|
+
* Dispose a texture's GPU resources and remove it from the registry.
|
|
2666
|
+
* Refcount-aware: if the key is still in use by a mounted `useTexture` consumer it is
|
|
2667
|
+
* skipped (with a warning) unless `{ force: true }` is passed.
|
|
2668
|
+
* @returns true if disposed, false if skipped.
|
|
2669
|
+
*/
|
|
2670
|
+
dispose(key: string, options?: DisposeOptions): boolean;
|
|
2671
|
+
/** Dispose every texture in the registry and clear it. Use on scene teardown. */
|
|
2672
|
+
disposeAll(): void;
|
|
2654
2673
|
}
|
|
2655
2674
|
/**
|
|
2656
|
-
*
|
|
2675
|
+
* Reactive Texture registry — load once with `useTexture`, reach the textures from anywhere.
|
|
2676
|
+
*
|
|
2677
|
+
* This is a registry of plain `Texture` objects (not TSL nodes), so the same texture can feed
|
|
2678
|
+
* a material map, a heightmap sampler, or anything else. It does **not** load — pair it with
|
|
2679
|
+
* `useTexture` for loading (registry enrollment is on by default); `useTextures` is for access and lifecycle.
|
|
2657
2680
|
*
|
|
2658
|
-
*
|
|
2659
|
-
*
|
|
2681
|
+
* The returned handle is **reactive**: the calling component re-renders when the registry
|
|
2682
|
+
* changes. Pass a selector to scope the subscription to a single read.
|
|
2660
2683
|
*
|
|
2661
2684
|
* @example
|
|
2662
2685
|
* ```tsx
|
|
2663
|
-
*
|
|
2664
|
-
*
|
|
2665
|
-
* // Check if texture is already cached
|
|
2666
|
-
* if (!has('/textures/diffuse.png')) {
|
|
2667
|
-
* // Load with useTexture and cache: true, or manually add
|
|
2668
|
-
* const tex = useTexture('/textures/diffuse.png', { cache: true })
|
|
2669
|
-
* }
|
|
2686
|
+
* // Load + register once (anywhere in the tree) — registered by default
|
|
2687
|
+
* useTexture({ map: '/diffuse.jpg', normalMap: '/normal.jpg' })
|
|
2670
2688
|
*
|
|
2671
|
-
* //
|
|
2672
|
-
* const
|
|
2673
|
-
*
|
|
2689
|
+
* // Reach them from another component — record form lands straight into a material
|
|
2690
|
+
* const { map, normalMap } = useTextures().get({ map: '/diffuse.jpg', normalMap: '/normal.jpg' })
|
|
2691
|
+
* return <meshStandardMaterial map={map} normalMap={normalMap} />
|
|
2674
2692
|
*
|
|
2675
|
-
* //
|
|
2676
|
-
*
|
|
2693
|
+
* // A set of heightmaps at once
|
|
2694
|
+
* const [a, b, c] = useTextures().get(['/h0.png', '/h1.png', '/h2.png'])
|
|
2677
2695
|
*
|
|
2678
|
-
* //
|
|
2679
|
-
*
|
|
2696
|
+
* // Register a non-URL texture (render target / procedural)
|
|
2697
|
+
* useTextures().add('rt-main', renderTarget.texture)
|
|
2680
2698
|
*
|
|
2681
|
-
* //
|
|
2682
|
-
*
|
|
2699
|
+
* // Deliberate GPU cleanup (refcount-aware; force to override)
|
|
2700
|
+
* useTextures().dispose('/diffuse.jpg')
|
|
2701
|
+
* useTextures().disposeAll() // scene teardown
|
|
2683
2702
|
* ```
|
|
2703
|
+
*
|
|
2704
|
+
* @remarks
|
|
2705
|
+
* **Future expansion:** an imperative async loader (e.g. `await useTextures().load('/x.jpg')`) is
|
|
2706
|
+
* intentionally not included yet. It would let non-React code (loading screens, dynamic streaming)
|
|
2707
|
+
* populate the registry without Suspense, at the cost of putting loading back into this hook. It
|
|
2708
|
+
* will be added only if a concrete consumer needs imperative loading; for now, loading lives in
|
|
2709
|
+
* `useTexture`.
|
|
2684
2710
|
*/
|
|
2685
2711
|
declare function useTextures(): UseTexturesReturn;
|
|
2712
|
+
declare function useTextures<T>(selector: (registry: UseTexturesReturn) => T): T;
|
|
2686
2713
|
|
|
2687
2714
|
/**
|
|
2688
2715
|
* Creates a render target compatible with the current renderer.
|
|
@@ -4379,4 +4406,4 @@ declare function isOnce(value: unknown): value is {
|
|
|
4379
4406
|
declare function Canvas(props: CanvasProps): react_jsx_runtime.JSX.Element;
|
|
4380
4407
|
|
|
4381
4408
|
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, three_d as ReactThreeFiber, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, context, createEvents, createPointerEvents, createPortal, createRoot, createStore, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, reconciler, registerPrimary, removeInteractivity, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useMutableCallback, useRenderTarget, useStore, useTexture, useTextures, useThree, waitForPrimary };
|
|
4382
|
-
export type { Act, AddPhaseOptions, Args, ArgsProp, AttachFnType, AttachType, BackgroundConfig, BackgroundProp, BaseRendererProps, Bridge, BufferLike, BufferRecord, BufferStore, Camera, CameraProps, CanvasProps, CanvasSchedulerConfig, Catalogue, Color, ColorManagementConfig, ComputeFunction, ConstructorRepresentation, DefaultGLProps, DefaultRendererProps, Disposable, DomEvent, Dpr, ElementProps, EnvironmentLoaderProps, EnvironmentProps, EquConfig, Euler, EventHandlers, EventManager, EventProps, Events, Extensions, FiberRoot, FilterFunction, FrameCallback, FrameControls, FrameNextCallback, FrameNextControls, FrameNextState, FrameState, FrameTimingState, Frameloop, GLProps, GLTFLike, GeometryProps, GeometryTransformProps, GlobalEffectType, GlobalRenderCallback, HostConfig, InferLoadResult, InjectState, InputLike, Instance, InstanceProps, InternalState, Intersection, IntersectionEvent, IsAllOptional, IsOptional, Layers, LegacyInternalState, LegacyRenderer, LegacyRootState, LoaderInstance, LoaderLike, LoaderResult, MappedTextureType, MathProps, MathRepresentation, MathType, MathTypes, Matrix3, Matrix4, Mutable, MutableOrReadonlyParameters, NodeProps, NonFunctionKeys, ObjectMap, OffscreenCanvas$1 as OffscreenCanvas, Overwrite, Performance, PointerCaptureTarget, PointerState, PresetsType, PrimaryCanvasEntry, Properties, Quaternion, R3FRenderer, RaycastableRepresentation, ReactProps, ReconcilerRoot, RenderCallback, RenderProps, RenderTargetOptions, Renderer, RendererConfigExtended, RendererFactory, RendererProps, Root, RootOptions, RootState, RootStore, SchedulerApi, SetBlock, Size, StorageLike, StorageRecord, StorageStore, Subscription, TSLNodeInput,
|
|
4409
|
+
export type { Act, AddPhaseOptions, Args, ArgsProp, AttachFnType, AttachType, BackgroundConfig, BackgroundProp, BaseRendererProps, Bridge, BufferLike, BufferRecord, BufferStore, Camera, CameraProps, CanvasProps, CanvasSchedulerConfig, Catalogue, Color, ColorManagementConfig, ComputeFunction, ConstructorRepresentation, DefaultGLProps, DefaultRendererProps, Disposable, DisposeOptions, DomEvent, Dpr, ElementProps, EnvironmentLoaderProps, EnvironmentProps, EquConfig, Euler, EventHandlers, EventManager, EventProps, Events, Extensions, FiberRoot, FilterFunction, FrameCallback, FrameControls, FrameNextCallback, FrameNextControls, FrameNextState, FrameState, FrameTimingState, Frameloop, GLProps, GLTFLike, GeometryProps, GeometryTransformProps, GlobalEffectType, GlobalRenderCallback, HostConfig, InferLoadResult, InjectState, InputLike, Instance, InstanceProps, InternalState, Intersection, IntersectionEvent, IsAllOptional, IsOptional, Layers, LegacyInternalState, LegacyRenderer, LegacyRootState, LoaderInstance, LoaderLike, LoaderResult, MappedTextureType, MathProps, MathRepresentation, MathType, MathTypes, Matrix3, Matrix4, Mutable, MutableOrReadonlyParameters, NodeProps, NonFunctionKeys, ObjectMap, OffscreenCanvas$1 as OffscreenCanvas, Overwrite, Performance, PointerCaptureTarget, PointerState, PresetsType, PrimaryCanvasEntry, Properties, Quaternion, R3FRenderer, RaycastableRepresentation, ReactProps, ReconcilerRoot, RenderCallback, RenderProps, RenderTargetOptions, Renderer, RendererConfigExtended, RendererFactory, RendererProps, Root, RootOptions, RootState, RootStore, SchedulerApi, SetBlock, Size, StorageLike, StorageRecord, StorageStore, Subscription, TSLNodeInput, TextureInput, TextureResult, ThreeCamera, ThreeElement, ThreeElements, ThreeElementsImpl, ThreeEvent, ThreeExports, ThreeToJSXElements, UnblockProps, UseFrameNextOptions, UseFrameOptions, UseTextureOptions, UseTexturesReturn, Vector2, Vector3, Vector4, VectorRepresentation, Viewport, VisibilityEntry, WebGLDefaultProps, WebGLProps, WebGLShadowConfig, XRManager, XRPointerConfig };
|