diff --git a/packages/website/src/components/GuessRenderer.tsx b/packages/website/src/components/GuessRenderer.tsx index 16403e519..a7f091924 100644 --- a/packages/website/src/components/GuessRenderer.tsx +++ b/packages/website/src/components/GuessRenderer.tsx @@ -1,6 +1,6 @@ -import { Canvas } from '@react-three/fiber'; import { GuessEphemeral } from '../stores/guessEphemeral'; import { TankopediaDisplay } from '../stores/tankopediaPersistent/constants'; +import { SmartCanvas } from './SmartCanvas'; import { Controls } from './Tankopedia/HeroSection/components/TankSandbox/components/Control'; import { Lighting } from './Tankopedia/HeroSection/components/TankSandbox/components/Lighting'; import { TankModel } from './Tankopedia/HeroSection/components/TankSandbox/components/TankModel'; @@ -13,7 +13,7 @@ export function GuessRenderer() { const isRevealed = guessState !== null; return ( - - + ); } diff --git a/packages/website/src/components/SmartCanvas.tsx b/packages/website/src/components/SmartCanvas.tsx new file mode 100644 index 000000000..fc2a24d07 --- /dev/null +++ b/packages/website/src/components/SmartCanvas.tsx @@ -0,0 +1,20 @@ +import { Canvas, type CanvasProps } from '@react-three/fiber'; +import { forwardRef, useImperativeHandle, useRef } from 'react'; +import { useOnScreen } from '../hooks/useOnScreen'; + +export const SmartCanvas = forwardRef( + (props, ref) => { + const canvas = useRef(null); + const onScreen = useOnScreen(canvas); + + useImperativeHandle(ref, () => canvas.current!, []); + + return ( + + ); + }, +); diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx index 74a3b4035..5207a9395 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CanvasContent.tsx @@ -1,4 +1,3 @@ -import { invalidate } from '@react-three/fiber'; import type { QuicklimeEvent } from 'quicklime'; import { useEffect, useRef } from 'react'; import type { Group } from 'three'; @@ -19,8 +18,6 @@ export function CanvasContent() { if (!gun.current) return; gun.current.rotation.x = event.data.pitch; - - invalidate(); } modelTransformEvent.on(handleModelTransformEvent); diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx index 9a91b910c..43ce564b2 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/FlexibilityCanvas.tsx @@ -1,19 +1,12 @@ -import { Canvas } from '@react-three/fiber'; +import { SmartCanvas } from '../../../../../../../SmartCanvas'; import { CameraPositioner, zoom } from './CameraPositioner'; import { CanvasContent } from './CanvasContent'; export function FlexibilityCanvas() { return ( - + - + ); } diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx index 41e0e2c28..b29cc2bcb 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx @@ -1,6 +1,6 @@ import { I_HAT, J_HAT } from '@blitzkit/core'; import { OrbitControls } from '@react-three/drei'; -import { invalidate, useThree } from '@react-three/fiber'; +import { invalidate, useFrame, useThree } from '@react-three/fiber'; import { useEffect, useRef } from 'react'; import { PerspectiveCamera, Vector3 } from 'three'; import { OrbitControls as OrbitControlsClass } from 'three-stdlib'; @@ -90,32 +90,16 @@ export function Controls({ -13, ).multiplyScalar(distanceScale); - useEffect(() => { - if (!orbitControls.current || !doAutoRotate) return; + const t0 = useRef(Date.now() / 1000); + useFrame(() => { + const now = Date.now() / 1000; + const t = now - t0.current; - const t0 = Date.now() / 1000; - let cancel = false; - - function frame() { - if (!cancel) requestAnimationFrame(frame); - - const now = Date.now() / 1000; - const t = now - t0; - - camera.position - .copy(inspectModeInitialPosition) - .applyAxisAngle(I_HAT, (Math.PI / 32) * Math.sin(t / 9)) - .applyAxisAngle(J_HAT, (-Math.PI / 16) * Math.sin(t / 7)); - - invalidate(); - } - - frame(); - - return () => { - cancel = true; - }; - }, [doAutoRotate, camera]); + camera.position + .copy(inspectModeInitialPosition) + .applyAxisAngle(I_HAT, (Math.PI / 32) * Math.sin(t / 9)) + .applyAxisAngle(J_HAT, (-Math.PI / 16) * Math.sin(t / 7)); + }); useEffect(() => { const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe( @@ -229,8 +213,6 @@ export function Controls({ }, [camera, protagonistTank.id, antagonistTank.id]); useEffect(() => { - let isInitialIteration = true; - function handleWheel(event: WheelEvent) { event.preventDefault(); } diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx index 49a314001..f213ceb71 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx @@ -1,5 +1,5 @@ import { BLITZKIT_TANK_ICON_SIZE } from '@blitzkit/core'; -import { Canvas, invalidate } from '@react-three/fiber'; +import { invalidate } from '@react-three/fiber'; import { forwardRef, Suspense, @@ -13,7 +13,6 @@ import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimi import { modelTransformEvent } from '../../../../../core/blitzkit/modelTransform'; import { Pose, poseEvent } from '../../../../../core/blitzkit/pose'; import { useEquipment } from '../../../../../hooks/useEquipment'; -import { useOnScreen } from '../../../../../hooks/useOnScreen'; import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition'; import { Duel } from '../../../../../stores/duel'; import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral'; @@ -26,6 +25,7 @@ import { StaticArmor, type ThicknessRange, } from '../../../../Armor/components/StaticArmor'; +import { SmartCanvas } from '../../../../SmartCanvas'; import { AutoClear } from './components/AutoClear'; import { Controls } from './components/Control'; import { InitialFogReveal } from './components/InitialFogReveal'; @@ -65,7 +65,6 @@ export const TankSandbox = forwardRef( const hideTankModelUnderArmor = TankopediaPersistent.use( (state) => state.hideTankModelUnderArmor, ); - const onScreen = useOnScreen(canvas); useEffect(() => { if (rawDisplay === display) return; @@ -204,10 +203,9 @@ export const TankSandbox = forwardRef( }, [display]); return ( - ( )} - + ); }, );