Add visible prop to toggle components and simplify conditional rendering

This commit is contained in:
geoffsee
2025-07-01 15:43:17 -04:00
committed by Geoff Seemueller
parent e72198628c
commit 6cc5e038a7
4 changed files with 57 additions and 49 deletions

View File

@@ -1,51 +1,51 @@
import { Box } from '@chakra-ui/react';
import { useEffect } from 'react';
import React, { memo, useEffect, useMemo } from 'react';
export interface BevySceneProps {
speed?: number; // transition seconds
intensity?: number;
speed?: number;
intensity?: number; // 0-1 when visible
glow?: boolean;
visible?: boolean; // NEW — defaults to true
}
export const BevyScene: React.FC<BevySceneProps> = ({ speed = 1, intensity = 1, glow = false }) => {
const BevySceneInner: React.FC<BevySceneProps> = ({
speed = 1,
intensity = 1,
glow = false,
visible,
}) => {
/* initialise once */
useEffect(() => {
let dispose: (() => void) | void;
(async () => {
const module = await import('/public/yachtpit.js', { type: 'module' });
console.log('init', module);
await module.default();
const { default: init } = await import(/* webpackIgnore: true */ '/public/yachtpit.js');
dispose = await init(); // zero-arg, uses #yachtpit-canvas
})();
// const script = document.createElement('script');
// script.src = '';
// script.type = 'module';
// document.body.appendChild(script);
// script.onload = loaded => {
// loaded.target?.init();
// console.log('loaded', loaded);
// };
return () => {
if (typeof dispose === 'function') dispose();
};
}, []);
/* memoised styles */
const wrapperStyles = useMemo(
() => ({
position: 'absolute' as const,
inset: 0,
zIndex: 0,
pointerEvents: 'none' as const,
opacity: visible ? Math.min(Math.max(intensity, 0), 1) : 0,
filter: glow ? 'blur(1px)' : 'none',
transition: `opacity ${speed}s ease-in-out`,
display: visible ? 'block' : 'none', // optional: reclaim hit-testing entirely
}),
[visible, intensity, glow, speed],
);
return (
<Box
pos="absolute"
inset={0}
zIndex={0}
pointerEvents="none"
opacity={Math.min(Math.max(intensity, 0), 1)}
filter={glow ? 'blur(1px)' : 'none'}
transition={`opacity ${speed}s ease-in-out`}
>
<script type="module"></script>
<canvas id="yachtpit-canvas" width="1280" height="720"></canvas>
{/*<iframe*/}
{/* src="/yachtpit.html"*/}
{/* style={{*/}
{/* width: '100%',*/}
{/* height: '100%',*/}
{/* border: 'none',*/}
{/* backgroundColor: 'transparent',*/}
{/* }}*/}
{/* title="Bevy Scene"*/}
{/*/>*/}
<Box as="div" sx={wrapperStyles}>
<canvas id="yachtpit-canvas" width={1280} height={720} aria-hidden />
</Box>
);
};
export const BevyScene = memo(BevySceneInner);

View File

@@ -34,7 +34,7 @@ export const LandingComponent: React.FC = () => {
<Tweakbox
sliders={{
speed: {
value: speed,
value: !particles ? speed : 0.99,
onChange: setSpeed,
label: 'Animation Speed',
min: 0.01,
@@ -43,7 +43,7 @@ export const LandingComponent: React.FC = () => {
ariaLabel: 'animation-speed',
},
intensity: {
value: intensity,
value: !particles ? intensity : 0.99,
onChange: setIntensity,
label: 'Effect Intensity',
min: 0.01,
@@ -94,9 +94,9 @@ export const LandingComponent: React.FC = () => {
}}
/>
</Box>
{!particles && !matrixRain && <BevyScene speed={speed} intensity={intensity} glow={glow} />}
{!particles && matrixRain && <MatrixRain speed={speed} intensity={intensity} glow={glow} />}
{particles && <Particles particles glow speed={speed} intensity={intensity} />}
<BevyScene speed={speed} intensity={intensity} glow={glow} visible={bevyScene} />
<MatrixRain speed={speed} intensity={intensity} glow={glow} visible={matrixRain} />
<Particles glow speed={speed} intensity={intensity} visible={particles} />
</Box>
);
};

View File

@@ -8,12 +8,14 @@ interface MatrixRainProps {
speed?: number;
glow?: boolean;
intensity?: number;
visible?: boolean;
}
export const MatrixRain: React.FC<MatrixRainProps> = ({
speed = 1,
glow = false,
intensity = 1,
visible,
}) => {
const fontSize = useBreakpointValue({ base: 14, md: 18, lg: 22 }) ?? 14;
const theme = useTheme();
@@ -111,7 +113,12 @@ export const MatrixRain: React.FC<MatrixRainProps> = ({
cancelAnimationFrame(animationRef.current);
}
};
}, [fontSize, speed, glow, intensity]);
}, [fontSize, speed, glow, intensity, visible]);
return <canvas ref={canvasRef} style={{ display: 'block' }} />;
return (
<canvas
ref={canvasRef}
style={{ display: visible ? 'block' : 'none', pointerEvents: 'none' }}
/>
);
};

View File

@@ -6,6 +6,7 @@ interface ParticlesProps {
intensity: number;
particles: boolean;
glow: boolean;
visible?: boolean;
}
interface Particle {
@@ -16,7 +17,7 @@ interface Particle {
size: number;
}
const Particles: React.FC<ParticlesProps> = ({ speed, intensity, particles, glow }) => {
const Particles: React.FC<ParticlesProps> = ({ speed, intensity, glow, visible }) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const particlesRef = useRef<Particle[]>([]);
const animationFrameRef = useRef<number | undefined>(undefined);
@@ -33,7 +34,7 @@ const Particles: React.FC<ParticlesProps> = ({ speed, intensity, particles, glow
// Main animation effect
useEffect(() => {
if (!particles) {
if (!visible) {
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
animationFrameRef.current = undefined;
@@ -128,11 +129,11 @@ const Particles: React.FC<ParticlesProps> = ({ speed, intensity, particles, glow
animationFrameRef.current = undefined;
}
};
}, [particles, intensity, speed, glow, theme.colors.text.accent]);
}, [visible, intensity, speed, glow, theme.colors.text.accent]);
// Separate effect for speed changes - update existing particle velocities
useEffect(() => {
if (!particles) return;
if (!visible) return;
particlesRef.current.forEach(particle => {
const currentSpeed = Math.sqrt(particle.vx * particle.vx + particle.vy * particle.vy);
@@ -146,13 +147,13 @@ const Particles: React.FC<ParticlesProps> = ({ speed, intensity, particles, glow
particle.vy = (Math.random() - 0.5) * speed;
}
});
}, [speed, particles]);
}, [speed, visible]);
return (
<Box zIndex={0} pointerEvents={'none'}>
<canvas
ref={canvasRef}
style={{ display: particles ? 'block' : 'none', pointerEvents: 'none' }}
style={{ display: visible ? 'block' : 'none', pointerEvents: 'none' }}
/>
</Box>
);