Fix R3F hooks used outside the Canvas
Move useTexture calls in the tile, token, and card viewers into child components rendered inside the Canvas. R3F hooks must run within the Canvas store, so calling them at the viewer's top level threw a runtime error.
This commit is contained in:
@@ -12,19 +12,26 @@ export default function CardViewer({ object }: { object: TTSObject }) {
|
|||||||
const deck = object.CustomDeck ? Object.values(object.CustomDeck)[0] : undefined;
|
const deck = object.CustomDeck ? Object.values(object.CustomDeck)[0] : undefined;
|
||||||
const faceUrl = deck?.FaceURL;
|
const faceUrl = deck?.FaceURL;
|
||||||
const backUrl = deck?.BackURL;
|
const backUrl = deck?.BackURL;
|
||||||
const face = faceUrl ? useTexture(assetUrl(faceUrl)) : null;
|
|
||||||
const back = backUrl ? useTexture(assetUrl(backUrl)) : null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scene>
|
<Scene>
|
||||||
<mesh>
|
<CardMesh faceUrl={faceUrl} backUrl={backUrl} />
|
||||||
<boxGeometry args={[1.4, 2, 0.06]} />
|
|
||||||
<meshStandardMaterial
|
|
||||||
color={face || back ? '#ffffff' : '#52525b'}
|
|
||||||
map={face ?? back ?? undefined}
|
|
||||||
roughness={0.6}
|
|
||||||
/>
|
|
||||||
</mesh>
|
|
||||||
</Scene>
|
</Scene>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rendered inside the Canvas so `useTexture` can access the R3F store.
|
||||||
|
function CardMesh({ faceUrl, backUrl }: { faceUrl?: string; backUrl?: string }) {
|
||||||
|
const face = faceUrl ? useTexture(assetUrl(faceUrl)) : null;
|
||||||
|
const back = backUrl ? useTexture(assetUrl(backUrl)) : null;
|
||||||
|
return (
|
||||||
|
<mesh>
|
||||||
|
<boxGeometry args={[1.4, 2, 0.06]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={face || back ? '#ffffff' : '#52525b'}
|
||||||
|
map={face ?? back ?? undefined}
|
||||||
|
roughness={0.6}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -9,19 +9,26 @@ import { assetUrl } from './assetUrl';
|
|||||||
*/
|
*/
|
||||||
export default function TileViewer({ object }: { object: TTSObject }) {
|
export default function TileViewer({ object }: { object: TTSObject }) {
|
||||||
const url = object.CustomImage?.ImageURL ?? object.CustomImage?.ImageSecondaryURL;
|
const url = object.CustomImage?.ImageURL ?? object.CustomImage?.ImageSecondaryURL;
|
||||||
const texture = url ? useTexture(assetUrl(url)) : null;
|
|
||||||
const thickness = object.CustomImage?.CustomTile?.Thickness ?? 0.1;
|
const thickness = object.CustomImage?.CustomTile?.Thickness ?? 0.1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scene>
|
<Scene>
|
||||||
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
<TileMesh url={url} thickness={thickness} />
|
||||||
<boxGeometry args={[1.6, 1.6, thickness]} />
|
|
||||||
<meshStandardMaterial
|
|
||||||
color={texture ? '#ffffff' : '#52525b'}
|
|
||||||
map={texture ?? undefined}
|
|
||||||
roughness={0.8}
|
|
||||||
/>
|
|
||||||
</mesh>
|
|
||||||
</Scene>
|
</Scene>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rendered inside the Canvas so `useTexture` can access the R3F store.
|
||||||
|
function TileMesh({ url, thickness }: { url?: string; thickness: number }) {
|
||||||
|
const texture = url ? useTexture(assetUrl(url)) : null;
|
||||||
|
return (
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
|
<boxGeometry args={[1.6, 1.6, thickness]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={texture ? '#ffffff' : '#52525b'}
|
||||||
|
map={texture ?? undefined}
|
||||||
|
roughness={0.8}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -9,19 +9,26 @@ import { assetUrl } from './assetUrl';
|
|||||||
*/
|
*/
|
||||||
export default function TokenViewer({ object }: { object: TTSObject }) {
|
export default function TokenViewer({ object }: { object: TTSObject }) {
|
||||||
const url = object.CustomImage?.ImageURL ?? object.CustomImage?.ImageSecondaryURL;
|
const url = object.CustomImage?.ImageURL ?? object.CustomImage?.ImageSecondaryURL;
|
||||||
const texture = url ? useTexture(assetUrl(url)) : null;
|
|
||||||
const thickness = object.CustomImage?.CustomToken?.Thickness ?? 0.1;
|
const thickness = object.CustomImage?.CustomToken?.Thickness ?? 0.1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scene>
|
<Scene>
|
||||||
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
<TokenMesh url={url} thickness={thickness} />
|
||||||
<cylinderGeometry args={[0.9, 0.9, thickness, 48]} />
|
|
||||||
<meshStandardMaterial
|
|
||||||
color={texture ? '#ffffff' : '#52525b'}
|
|
||||||
map={texture ?? undefined}
|
|
||||||
roughness={0.8}
|
|
||||||
/>
|
|
||||||
</mesh>
|
|
||||||
</Scene>
|
</Scene>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rendered inside the Canvas so `useTexture` can access the R3F store.
|
||||||
|
function TokenMesh({ url, thickness }: { url?: string; thickness: number }) {
|
||||||
|
const texture = url ? useTexture(assetUrl(url)) : null;
|
||||||
|
return (
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
|
<cylinderGeometry args={[0.9, 0.9, thickness, 48]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={texture ? '#ffffff' : '#52525b'}
|
||||||
|
map={texture ?? undefined}
|
||||||
|
roughness={0.8}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user