Browse Source

initial commit

master
Stephanie Gredell 4 weeks ago
commit
8314f02f85
  1. 1
      .gitignore
  2. 28
      index.html
  3. 2524
      package-lock.json
  4. 24
      package.json
  5. 29
      src/App.jsx
  6. 778
      src/Scene.jsx
  7. 9
      src/main.jsx
  8. 48
      style.css
  9. 10
      vite.config.js

1
.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
node_modules

28
index.html

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Disco Party 🕺</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
font-family: 'Arial', sans-serif;
background: #000;
}
#root {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

2524
package-lock.json generated

File diff suppressed because it is too large Load Diff

24
package.json

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
{
"name": "disco-party",
"version": "1.0.0",
"description": "3D Disco Party Scene with React Three Fiber",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@react-three/fiber": "^8.15.11",
"@react-three/drei": "^9.88.13",
"three": "^0.160.0"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.0"
}
}

29
src/App.jsx

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
import Scene from './Scene';
function App() {
return (
<Canvas
shadows
camera={{ position: [0, 8, 12], fov: 75 }}
gl={{ antialias: true }}
>
<color attach="background" args={['#050505']} />
<fog attach="fog" args={['#050505', 15, 50]} />
<ambientLight intensity={0.2} />
<Scene />
<OrbitControls
enableDamping
dampingFactor={0.05}
minDistance={5}
maxDistance={30}
/>
</Canvas>
);
}
export default App;

778
src/Scene.jsx

@ -0,0 +1,778 @@ @@ -0,0 +1,778 @@
import { useRef, useMemo } from 'react';
import { useFrame } from '@react-three/fiber';
import { SpotLight, Text } from '@react-three/drei';
import * as THREE from 'three';
function DanceFloor() {
return (
<mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
<planeGeometry args={[30, 30]} />
<meshStandardMaterial
color="#8b4513"
roughness={0.6}
metalness={0.0}
/>
</mesh>
);
}
function Balloons() {
const balloons = useMemo(() => {
const positions = [];
for (let i = 0; i < 15; i++) {
positions.push([
(Math.random() - 0.5) * 25,
2 + Math.random() * 8,
(Math.random() - 0.5) * 25
]);
}
return positions;
}, []);
return (
<>
{balloons.map((pos, i) => (
<group key={i} position={pos}>
<mesh>
<sphereGeometry args={[0.3, 16, 16]} />
<meshStandardMaterial
color={['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff'][i % 6]}
roughness={0.3}
metalness={0.1}
/>
</mesh>
<mesh position={[0, -0.3, 0]}>
<cylinderGeometry args={[0.01, 0.01, 1, 8]} />
<meshStandardMaterial color="#333" />
</mesh>
</group>
))}
</>
);
}
function Confetti() {
const confettiRef = useRef();
const count = 250;
const positions = useMemo(() => {
const pos = new Float32Array(count * 3);
for (let i = 0; i < count * 3; i += 3) {
pos[i] = (Math.random() - 0.5) * 30;
pos[i + 1] = Math.random() * 15;
pos[i + 2] = (Math.random() - 0.5) * 30;
}
return pos;
}, []);
const colors = useMemo(() => {
const cols = new Float32Array(count * 3);
const colorArray = [
[1, 0, 0], [0, 1, 0], [0, 0, 1],
[1, 1, 0], [1, 0, 1], [0, 1, 1]
];
for (let i = 0; i < count; i++) {
const color = colorArray[Math.floor(Math.random() * colorArray.length)];
cols[i * 3] = color[0];
cols[i * 3 + 1] = color[1];
cols[i * 3 + 2] = color[2];
}
return cols;
}, []);
useFrame((state) => {
if (confettiRef.current) {
confettiRef.current.rotation.y += 0.001;
const positions = confettiRef.current.geometry.attributes.position.array;
for (let i = 1; i < positions.length; i += 3) {
positions[i] -= 0.01;
if (positions[i] < 0) {
positions[i] = 15;
}
}
confettiRef.current.geometry.attributes.position.needsUpdate = true;
}
});
return (
<points ref={confettiRef}>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
count={count}
array={positions}
itemSize={3}
/>
<bufferAttribute
attach="attributes-color"
count={count}
array={colors}
itemSize={3}
/>
</bufferGeometry>
<pointsMaterial
size={0.1}
vertexColors
transparent
opacity={0.8}
blending={THREE.AdditiveBlending}
/>
</points>
);
}
function Person({ position, index, lookAt }) {
const groupRef = useRef();
const leftArmRef = useRef();
const rightArmRef = useRef();
// Randomize skin tones
const skinTones = ['#ffdbac', '#f1c27d', '#e0ac69', '#c68642', '#8d5524'];
const skinColor = skinTones[index % skinTones.length];
// More color variety for shirts
const shirtColors = [
'#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7',
'#a29bfe', '#fd79a8', '#00b894', '#e17055', '#74b9ff',
'#a29bfe', '#fd79a8', '#fdcb6e', '#e84393', '#00cec9'
];
const shirtColor = shirtColors[index % shirtColors.length];
useFrame(() => {
if (groupRef.current && lookAt) {
// Face the person they're talking to
const dx = lookAt[0] - position[0];
const dz = lookAt[2] - position[2];
groupRef.current.rotation.y = Math.atan2(dx, dz);
// Subtle idle animation - slight head/body movement
const t = Date.now() * 0.005;
const offset = index * 0.3;
groupRef.current.rotation.y += Math.sin(t * 0.05 + offset) * 0.05;
// Subtle arm gestures while talking
if (leftArmRef.current) {
leftArmRef.current.rotation.x = Math.sin(t * 1.7 + offset) * 0.1;
leftArmRef.current.rotation.z = Math.sin(t * 1.5 + offset) * 0.05;
}
if (rightArmRef.current) {
rightArmRef.current.rotation.x = Math.sin(t * 1.5 + offset + 1) * 0.1;
rightArmRef.current.rotation.z = Math.sin(t * 1.5 + offset + 1) * 0.05;
}
}
});
return (
<group ref={groupRef} position={position}>
{/* Head */}
<mesh position={[0, 1.45, 0]}>
<sphereGeometry args={[0.15, 16, 16]} />
<meshStandardMaterial color={skinColor} />
</mesh>
{/* Torso */}
<mesh position={[0, 1.1, 0]}>
<boxGeometry args={[0.35, 0.5, 0.25]} />
<meshStandardMaterial color={shirtColor} />
</mesh>
{/* Left Arm */}
<group ref={leftArmRef} position={[-0.18, 1.1, 0]}>
<mesh position={[-0.15, 0, 0]}>
<boxGeometry args={[0.3, 0.12, 0.12]} />
<meshStandardMaterial color={skinColor} />
</mesh>
</group>
{/* Right Arm */}
<group ref={rightArmRef} position={[0.18, 1.1, 0]}>
<mesh position={[0.15, 0, 0]}>
<boxGeometry args={[0.3, 0.12, 0.12]} />
<meshStandardMaterial color={skinColor} />
</mesh>
</group>
{/* Left Leg - standing still */}
<mesh position={[-0.1, 0.7, 0]}>
<boxGeometry args={[0.12, 0.7, 0.12]} />
<meshStandardMaterial color="#333" />
</mesh>
<mesh position={[-0.1, 0.25, 0.05]}>
<boxGeometry args={[0.15, 0.1, 0.2]} />
<meshStandardMaterial color="#222" />
</mesh>
{/* Right Leg - standing still */}
<mesh position={[0.1, 0.7, 0]}>
<boxGeometry args={[0.12, 0.7, 0.12]} />
<meshStandardMaterial color="#333" />
</mesh>
<mesh position={[0.1, 0.25, 0.05]}>
<boxGeometry args={[0.15, 0.1, 0.2]} />
<meshStandardMaterial color="#222" />
</mesh>
</group>
);
}
function People() {
// Create groups of people talking to each other - 80 total people
const groups = useMemo(() => {
const peopleGroups = [];
const groupCount = 180; // 30 groups
for (let g = 0; g < groupCount; g++) {
const groupAngle = (g / groupCount) * Math.PI * 3;
const groupRadius = 2 + Math.random() * 10; // Spread around the room
const groupCenter = [
Math.cos(groupAngle) * groupRadius,
0,
Math.sin(groupAngle) * groupRadius
];
// Vary group sizes to get close to 80 total (mostly groups of 3, some 2)
const peopleInGroup = g < 25 ? 3 : 2;
const group = [];
for (let p = 0; p < peopleInGroup; p++) {
const personAngle = (p / peopleInGroup) * Math.PI * 2;
const personRadius = 0.8;
const personPos = [
groupCenter[0] + Math.cos(personAngle) * personRadius,
0,
groupCenter[2] + Math.sin(personAngle) * personRadius
];
// Person they're looking at (next person in circle, or center)
const lookAtIndex = (p + 1) % peopleInGroup;
const lookAtPos = [
groupCenter[0] + Math.cos((lookAtIndex / peopleInGroup) * Math.PI * 2) * personRadius,
0,
groupCenter[2] + Math.sin((lookAtIndex / peopleInGroup) * Math.PI * 2) * personRadius
];
group.push({ position: personPos, lookAt: lookAtPos });
}
peopleGroups.push(...group);
}
return peopleGroups;
}, []);
return (
<>
{groups.map((person, i) => (
<Person key={i} position={person.position} index={i} lookAt={person.lookAt} />
))}
</>
);
}
function YouTubeBanner() {
// Create triangle geometry for play button
const triangleShape = useMemo(() => {
const shape = new THREE.Shape();
shape.moveTo(0, 0.4);
shape.lineTo(0.7, 0);
shape.lineTo(0, -0.4);
shape.lineTo(0, 0.4);
return shape;
}, []);
return (
<group position={[0, -1, 0.1]}>
{/* Red background */}
<mesh>
<planeGeometry args={[5, 2]} />
<meshStandardMaterial color="#ff0000" />
</mesh>
{/* White play button triangle */}
<mesh position={[0, 0, 0.01]}>
<shapeGeometry args={[triangleShape]} />
<meshStandardMaterial color="#ffffff" />
</mesh>
{/* YouTube text */}
<Text
position={[0.3, 0, 0.01]}
fontSize={0.35}
color="#ffffff"
anchorX="left"
anchorY="middle"
fontWeight="bold"
>
YouTube
</Text>
</group>
);
}
function DJ() {
const groupRef = useRef();
const leftArmRef = useRef();
const rightArmRef = useRef();
useFrame((state) => {
if (groupRef.current) {
const t = state.clock.elapsedTime;
// Subtle head bobbing to the beat
groupRef.current.position.y = Math.sin(t * 2) * 0.05;
// Arm movements - mixing/scratching
if (leftArmRef.current) {
leftArmRef.current.rotation.x = Math.sin(t * 3) * 0.2;
leftArmRef.current.rotation.z = Math.sin(t * 3) * 0.1;
}
if (rightArmRef.current) {
rightArmRef.current.rotation.x = Math.sin(t * 3 + 1) * 0.2;
rightArmRef.current.rotation.z = Math.sin(t * 3 + 1) * 0.1;
}
}
});
return (
<group ref={groupRef} position={[0, 2, -13.3]}>
{/* Head */}
<mesh position={[0, 1.6, 0]}>
<sphereGeometry args={[0.18, 16, 16]} />
<meshStandardMaterial color="#d4a574" />
</mesh>
{/* Headphones */}
<mesh position={[0, 1.6, 0]} rotation={[0, 0, 0]}>
<torusGeometry args={[0.25, 0.05, 8, 16]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
<mesh position={[-0.25, 1.6, 0]}>
<cylinderGeometry args={[0.12, 0.12, 0.15, 16]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
<mesh position={[0.25, 1.6, 0]}>
<cylinderGeometry args={[0.12, 0.12, 0.15, 16]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
{/* Torso */}
<mesh position={[0, 1.1, 0]}>
<boxGeometry args={[0.35, 0.5, 0.25]} />
<meshStandardMaterial color="#000000" />
</mesh>
{/* Left Arm */}
<group ref={leftArmRef} position={[-0.25, 1.1, 0]}>
<mesh position={[-0.15, 0, 0]}>
<boxGeometry args={[0.3, 0.12, 0.12]} />
<meshStandardMaterial color="#d4a574" />
</mesh>
</group>
{/* Right Arm */}
<group ref={rightArmRef} position={[0.25, 1.1, 0]}>
<mesh position={[0.15, 0, 0]}>
<boxGeometry args={[0.3, 0.12, 0.12]} />
<meshStandardMaterial color="#d4a574" />
</mesh>
</group>
{/* Legs */}
<mesh position={[-0.1, 0.7, 0]}>
<boxGeometry args={[0.12, 0.7, 0.12]} />
<meshStandardMaterial color="#333" />
</mesh>
<mesh position={[0.1, 0.7, 0]}>
<boxGeometry args={[0.12, 0.7, 0.12]} />
<meshStandardMaterial color="#333" />
</mesh>
{/* Shoes */}
<mesh position={[-0.1, 0.25, 0.05]}>
<boxGeometry args={[0.18, 0.1, 0.25]} />
<meshStandardMaterial color="#0a0a0a" />
</mesh>
<mesh position={[0.1, 0.25, 0.05]}>
<boxGeometry args={[0.18, 0.1, 0.25]} />
<meshStandardMaterial color="#0a0a0a" />
</mesh>
</group>
);
}
function DJBooth() {
return (
<group position={[0, 0, -14]}>
{/* Bar base - larger and more prominent */}
<mesh position={[0, 0.5, 0]}>
<boxGeometry args={[6, 1, 2]} />
<meshStandardMaterial color="#2a1a0a" roughness={0.3} metalness={0.2} />
</mesh>
{/* Bar top */}
<mesh position={[0, 1.2, 0]}>
<boxGeometry args={[6.2, 0.2, 2.2]} />
<meshStandardMaterial color="#1a0a0a" roughness={0.1} metalness={0.5} />
</mesh>
{/* DJ equipment section - raised */}
<mesh position={[0, 2, 0.6]}>
<boxGeometry args={[4, 1.5, 0.8]} />
<meshStandardMaterial color="#0a0a0a" />
</mesh>
{/* Equipment panel */}
<mesh position={[0, 2.5, 0.61]}>
<boxGeometry args={[3.5, 0.4, 0.1]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
{/* Control buttons - more prominent */}
<mesh position={[-1.2, 2.5, 0.62]}>
<cylinderGeometry args={[0.2, 0.2, 0.08, 16]} />
<meshStandardMaterial color="#ff0000" emissive="#ff0000" emissiveIntensity={0.5} />
</mesh>
<mesh position={[0, 2.5, 0.62]}>
<cylinderGeometry args={[0.2, 0.2, 0.08, 16]} />
<meshStandardMaterial color="#00ff00" emissive="#00ff00" emissiveIntensity={0.5} />
</mesh>
<mesh position={[1.2, 2.5, 0.62]}>
<cylinderGeometry args={[0.2, 0.2, 0.08, 16]} />
<meshStandardMaterial color="#0000ff" emissive="#0000ff" emissiveIntensity={0.5} />
</mesh>
{/* Bar stools */}
<mesh position={[-2.5, 0.6, -1.2]} rotation={[0, 0, 0]}>
<cylinderGeometry args={[0.15, 0.15, 1.2, 16]} />
<meshStandardMaterial color="#654321" />
</mesh>
<mesh position={[-2.5, 1.2, -1.2]}>
<cylinderGeometry args={[0.4, 0.4, 0.1, 16]} />
<meshStandardMaterial color="#8b4513" />
</mesh>
<mesh position={[2.5, 0.6, -1.2]} rotation={[0, 0, 0]}>
<cylinderGeometry args={[0.15, 0.15, 1.2, 16]} />
<meshStandardMaterial color="#654321" />
</mesh>
<mesh position={[2.5, 1.2, -1.2]}>
<cylinderGeometry args={[0.4, 0.4, 0.1, 16]} />
<meshStandardMaterial color="#8b4513" />
</mesh>
{/* Banner hanging from above - bigger and more prominent */}
<group position={[0, 5.5, 0]}>
{/* YouTube logo banner background */}
<YouTubeBanner />
{/* Banner text - bigger */}
<Text
position={[0, -1, 0.12]}
rotation={[0, 0, 0]}
fontSize={0.4}
color="#ffffff"
anchorX="center"
anchorY="middle"
fontWeight="bold"
outlineWidth={0.02}
outlineColor="#000000"
>
1 MILLION SUBSCRIBERS
</Text>
{/* Rope/string to hang it */}
</group>
{/* Spotlight on the bar */}
<pointLight position={[0, 5, -14]} intensity={50} distance={15} color="#ffffff" />
</group>
);
}
function DJBoothSpotlight() {
const spotlightRef = useRef();
const targetRef = useRef();
useFrame(() => {
if (spotlightRef.current && targetRef.current) {
spotlightRef.current.target = targetRef.current;
}
});
return (
<group>
<spotLight
ref={spotlightRef}
position={[0, 10, -14]}
angle={Math.PI / 6}
penumbra={0.3}
intensity={300}
distance={20}
decay={1}
color="#ffffff"
castShadow
/>
<object3D ref={targetRef} position={[0, 2, -14]} />
</group>
);
}
function Speakers() {
return (
<>
<group position={[-14, 0, 0]}>
<mesh position={[0, 1.5, 0]}>
<boxGeometry args={[1, 3, 1]} />
<meshStandardMaterial color="#222" />
</mesh>
<mesh position={[0, 1.5, 0.51]}>
<cylinderGeometry args={[0.4, 0.4, 0.1, 32]} />
<meshStandardMaterial color="#111" />
</mesh>
</group>
<group position={[14, 0, 0]}>
<mesh position={[0, 1.5, 0]}>
<boxGeometry args={[1, 3, 1]} />
<meshStandardMaterial color="#222" />
</mesh>
<mesh position={[0, 1.5, 0.51]}>
<cylinderGeometry args={[0.4, 0.4, 0.1, 32]} />
<meshStandardMaterial color="#111" />
</mesh>
</group>
</>
);
}
function ThePrimeagen() {
const groupRef = useRef();
const leftArmRef = useRef();
const rightArmRef = useRef();
useFrame((state) => {
if (groupRef.current) {
const t = state.clock.elapsedTime;
// Subtle animation
groupRef.current.rotation.y = Math.sin(t * 0.5) * 0.1;
if (leftArmRef.current) {
leftArmRef.current.rotation.x = Math.sin(t * 2) * 0.2;
}
if (rightArmRef.current) {
rightArmRef.current.rotation.x = -Math.sin(t * 2) * 0.2;
}
}
});
return (
<group ref={groupRef} position={[10, 0, -8]}>
{/* Head */}
<mesh position={[0, 1.6, 0]}>
<sphereGeometry args={[0.18, 16, 16]} />
<meshStandardMaterial color="#d4a574" />
</mesh>
{/* Beard */}
<mesh position={[0, 1.45, 0.12]}>
<boxGeometry args={[0.25, 0.2, 0.08]} />
<meshStandardMaterial color="#2a2a2a" />
</mesh>
<mesh position={[-0.08, 1.4, 0.12]}>
<boxGeometry args={[0.1, 0.15, 0.08]} />
<meshStandardMaterial color="#2a2a2a" />
</mesh>
<mesh position={[0.08, 1.4, 0.12]}>
<boxGeometry args={[0.1, 0.15, 0.08]} />
<meshStandardMaterial color="#2a2a2a" />
</mesh>
{/* Glasses */}
<mesh position={[-0.08, 1.58, 0.1]}>
<torusGeometry args={[0.06, 0.01, 8, 16]} />
<meshStandardMaterial color="#1a1a1a" metalness={0.8} roughness={0.2} />
</mesh>
<mesh position={[0.08, 1.58, 0.1]}>
<torusGeometry args={[0.06, 0.01, 8, 16]} />
<meshStandardMaterial color="#1a1a1a" metalness={0.8} roughness={0.2} />
</mesh>
{/* Bridge */}
<mesh position={[0, 1.58, 0.1]} rotation={[0, 0, Math.PI / 2]}>
<boxGeometry args={[0.16, 0.01, 0.01]} />
<meshStandardMaterial color="#1a1a1a" metalness={0.8} roughness={0.2} />
</mesh>
{/* Hoodie */}
<mesh position={[0, 1.1, 0]}>
<boxGeometry args={[0.5, 0.6, 0.3]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
{/* Hood */}
<mesh position={[0, 1.5, -0.05]}>
<coneGeometry args={[0.3, 0.3, 8]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
{/* Left Arm */}
<group ref={leftArmRef} position={[-0.3, 1.1, 0]}>
<mesh position={[-0.15, 0, 0]}>
<boxGeometry args={[0.3, 0.15, 0.15]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
</group>
{/* Right Arm */}
<group ref={rightArmRef} position={[0.3, 1.1, 0]}>
<mesh position={[0.15, 0, 0]}>
<boxGeometry args={[0.3, 0.15, 0.15]} />
<meshStandardMaterial color="#1a1a1a" />
</mesh>
</group>
{/* Legs */}
<mesh position={[-0.1, 0.7, 0]}>
<boxGeometry args={[0.15, 0.7, 0.15]} />
<meshStandardMaterial color="#2a2a2a" />
</mesh>
<mesh position={[0.1, 0.7, 0]}>
<boxGeometry args={[0.15, 0.7, 0.15]} />
<meshStandardMaterial color="#2a2a2a" />
</mesh>
{/* Shoes */}
<mesh position={[-0.1, 0.25, 0.05]}>
<boxGeometry args={[0.18, 0.1, 0.25]} />
<meshStandardMaterial color="#0a0a0a" />
</mesh>
<mesh position={[0.1, 0.25, 0.05]}>
<boxGeometry args={[0.18, 0.1, 0.25]} />
<meshStandardMaterial color="#0a0a0a" />
</mesh>
</group>
);
}
function Scene() {
const spot1Ref = useRef();
const spot2Ref = useRef();
const spot3Ref = useRef();
const spot4Ref = useRef();
const spot5Ref = useRef();
useFrame((state) => {
const t = state.clock.elapsedTime;
if (spot1Ref.current) {
const phase = t * 0.6;
spot1Ref.current.target.position.x = Math.cos(phase) * 3;
spot1Ref.current.target.position.z = Math.sin(phase) * 3;
spot1Ref.current.target.position.y = 2.5 + Math.sin(t * 1.2) * 0.5;
}
if (spot2Ref.current) {
const phase = t * 0.6 + (Math.PI * 2 / 5);
spot2Ref.current.target.position.x = Math.cos(phase) * 3;
spot2Ref.current.target.position.z = Math.sin(phase) * 3;
spot2Ref.current.target.position.y = 2.5 + Math.sin(t * 1.2) * 0.5;
}
if (spot3Ref.current) {
const phase = t * 0.6 + (Math.PI * 4 / 5);
spot3Ref.current.target.position.x = Math.cos(phase) * 3;
spot3Ref.current.target.position.z = Math.sin(phase) * 3;
spot3Ref.current.target.position.y = 2.5 + Math.sin(t * 1.2) * 0.5;
}
if (spot4Ref.current) {
const phase = t * 0.6 + (Math.PI * 6 / 5);
spot4Ref.current.target.position.x = Math.cos(phase) * 3;
spot4Ref.current.target.position.z = Math.sin(phase) * 3;
spot4Ref.current.target.position.y = 2.5 + Math.sin(t * 1.2) * 0.5;
}
if (spot5Ref.current) {
const phase = t * 0.6 + (Math.PI * 8 / 5);
spot5Ref.current.target.position.x = Math.cos(phase) * 3;
spot5Ref.current.target.position.z = Math.sin(phase) * 3;
spot5Ref.current.target.position.y = 2.5 + Math.sin(t * 1.2) * 0.5;
}
});
return (
<>
<DanceFloor />
<Balloons />
<Confetti />
<People />
<ThePrimeagen />
<DJBooth />
<DJ />
<DJBoothSpotlight />
<Speakers />
<SpotLight
ref={spot1Ref}
position={[10, 12, 10]}
angle={Math.PI / 7}
penumbra={0.5}
intensity={250}
distance={60}
decay={1}
color="#ff3366"
castShadow
/>
<SpotLight
ref={spot2Ref}
position={[-10, 12, 10]}
angle={Math.PI / 7}
penumbra={0.5}
intensity={250}
distance={60}
decay={1}
color="#33ffcc"
castShadow
/>
<SpotLight
ref={spot3Ref}
position={[0, 12, -12]}
angle={Math.PI / 7}
penumbra={0.5}
intensity={250}
distance={60}
decay={1}
color="#3366ff"
castShadow
/>
<SpotLight
ref={spot4Ref}
position={[-10, 12, -10]}
angle={Math.PI / 7}
penumbra={0.5}
intensity={250}
distance={60}
decay={1}
color="#ffff00"
castShadow
/>
<SpotLight
ref={spot5Ref}
position={[10, 12, -10]}
angle={Math.PI / 7}
penumbra={0.5}
intensity={250}
distance={60}
decay={1}
color="#ff00ff"
castShadow
/>
</>
);
}
export default Scene;

9
src/main.jsx

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

48
style.css

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
font-family: 'Arial', sans-serif;
background: #000;
}
#container {
width: 100vw;
height: 100vh;
}
#info {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: #fff;
z-index: 100;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
pointer-events: none;
}
#info h1 {
font-size: 2.5em;
margin-bottom: 10px;
animation: pulse 2s ease-in-out infinite;
}
#info p {
font-size: 1em;
opacity: 0.8;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}

10
vite.config.js

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
open: true
}
});
Loading…
Cancel
Save