Initial commit gov-llm-v2
This commit is contained in:
201
components/VisualEffects.tsx
Executable file
201
components/VisualEffects.tsx
Executable file
@@ -0,0 +1,201 @@
|
||||
|
||||
import React, { useRef, useMemo, useEffect } from 'react';
|
||||
import { Canvas, useFrame } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
|
||||
// Add global declaration to fix TypeScript errors with React Three Fiber elements
|
||||
declare module 'react' {
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
points: any;
|
||||
bufferGeometry: any;
|
||||
bufferAttribute: any;
|
||||
pointsMaterial: any;
|
||||
ambientLight: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
points: any;
|
||||
bufferGeometry: any;
|
||||
bufferAttribute: any;
|
||||
pointsMaterial: any;
|
||||
ambientLight: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- WARP EFFECT ---
|
||||
const WarpParticles = () => {
|
||||
const count = 2000;
|
||||
const mesh = useRef<THREE.Points>(null);
|
||||
|
||||
// Particles setup
|
||||
const particles = useMemo(() => {
|
||||
const temp = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const x = (Math.random() - 0.5) * 30;
|
||||
const y = (Math.random() - 0.5) * 60; // Taller spread
|
||||
const z = (Math.random() - 0.5) * 20;
|
||||
temp.push(x, y, z);
|
||||
}
|
||||
return new Float32Array(temp);
|
||||
}, [count]);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
if (!mesh.current) return;
|
||||
|
||||
const time = state.clock.getElapsedTime();
|
||||
|
||||
// Logic:
|
||||
// 1. Initial burst (0-1s): Speed = 3.0
|
||||
// 2. Slow down (1s+): Speed = 0.5 (2x slower than a standard '1.0' baseline)
|
||||
|
||||
let targetSpeed = 0.5; // Slow cruising speed
|
||||
|
||||
if (time < 1.0) {
|
||||
targetSpeed = 4.0; // Fast entry
|
||||
} else if (time < 1.8) {
|
||||
// Smooth deceleration phase
|
||||
const t = (time - 1.0) / 0.8;
|
||||
targetSpeed = THREE.MathUtils.lerp(4.0, 0.5, t);
|
||||
}
|
||||
|
||||
const positions = mesh.current.geometry.attributes.position.array as Float32Array;
|
||||
const moveY = targetSpeed * delta * 10; // Scale speed to movement
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
// Move particles up
|
||||
positions[i * 3 + 1] += moveY;
|
||||
|
||||
// Seamless wrap around
|
||||
if (positions[i * 3 + 1] > 30) {
|
||||
positions[i * 3 + 1] -= 60; // Subtract height to wrap seamlessly
|
||||
// Randomize X/Z on respawn to create new star patterns
|
||||
positions[i * 3] = (Math.random() - 0.5) * 30;
|
||||
positions[i * 3 + 2] = (Math.random() - 0.5) * 20;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.current.geometry.attributes.position.needsUpdate = true;
|
||||
|
||||
// Stretch effect based on speed
|
||||
// Higher speed = more vertical stretch
|
||||
mesh.current.scale.y = 1 + targetSpeed * 0.5;
|
||||
});
|
||||
|
||||
return (
|
||||
<points ref={mesh}>
|
||||
<bufferGeometry>
|
||||
<bufferAttribute
|
||||
attach="attributes-position"
|
||||
count={particles.length / 3}
|
||||
array={particles}
|
||||
itemSize={3}
|
||||
/>
|
||||
</bufferGeometry>
|
||||
<pointsMaterial
|
||||
size={0.08}
|
||||
color="#ffffff"
|
||||
transparent
|
||||
opacity={0.6}
|
||||
sizeAttenuation
|
||||
blending={THREE.AdditiveBlending}
|
||||
depthWrite={false}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
||||
|
||||
export const WarpOverlay = () => {
|
||||
return (
|
||||
<div className="absolute inset-0 z-40 pointer-events-none mix-blend-screen">
|
||||
<Canvas
|
||||
camera={{ position: [0, 0, 15], fov: 60 }}
|
||||
gl={{ alpha: true }}
|
||||
style={{ pointerEvents: 'none' }} // Explicitly disable pointer events on canvas element
|
||||
>
|
||||
<WarpParticles />
|
||||
</Canvas>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// --- SAND EFFECT ---
|
||||
const SandParticles = () => {
|
||||
const count = 4000;
|
||||
const mesh = useRef<THREE.Points>(null);
|
||||
|
||||
const particles = useMemo(() => {
|
||||
const temp = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const x = (Math.random() - 0.5) * 25;
|
||||
const y = (Math.random() - 0.5) * 25;
|
||||
const z = (Math.random() - 0.5) * 10;
|
||||
temp.push(x, y, z);
|
||||
}
|
||||
return new Float32Array(temp);
|
||||
}, [count]);
|
||||
|
||||
useFrame((state) => {
|
||||
if (!mesh.current) return;
|
||||
|
||||
const positions = mesh.current.geometry.attributes.position.array as Float32Array;
|
||||
const time = state.clock.getElapsedTime();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const ix = i * 3;
|
||||
const iy = i * 3 + 1;
|
||||
const iz = i * 3 + 2;
|
||||
|
||||
// Chaotic wind movement
|
||||
positions[ix] += Math.sin(time * 0.5 + positions[iy] * 0.5) * 0.02;
|
||||
positions[iy] += Math.cos(time * 0.3 + positions[ix] * 0.5) * 0.01;
|
||||
|
||||
// Wrap around
|
||||
if (Math.abs(positions[ix]) > 12) positions[ix] *= -0.9;
|
||||
if (Math.abs(positions[iy]) > 12) positions[iy] *= -0.9;
|
||||
}
|
||||
mesh.current.geometry.attributes.position.needsUpdate = true;
|
||||
mesh.current.rotation.y = time * 0.05;
|
||||
});
|
||||
|
||||
return (
|
||||
<points ref={mesh}>
|
||||
<bufferGeometry>
|
||||
<bufferAttribute
|
||||
attach="attributes-position"
|
||||
count={particles.length / 3}
|
||||
array={particles}
|
||||
itemSize={3}
|
||||
/>
|
||||
</bufferGeometry>
|
||||
<pointsMaterial
|
||||
size={0.05}
|
||||
color="#c4c3be"
|
||||
transparent
|
||||
opacity={0.8}
|
||||
sizeAttenuation
|
||||
depthWrite={false}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
||||
|
||||
export const SandOverlay = () => {
|
||||
return (
|
||||
<div className="absolute inset-0 z-40 pointer-events-none">
|
||||
<Canvas
|
||||
camera={{ position: [0, 0, 10], fov: 60 }}
|
||||
gl={{ alpha: true }}
|
||||
style={{ pointerEvents: 'none' }} // Explicitly disable pointer events on canvas element
|
||||
>
|
||||
<ambientLight intensity={1} />
|
||||
<SandParticles />
|
||||
</Canvas>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user