React/TypeScript Demo
Демонстрация возможностей создания интерактивных компонентов с помощью React и TypeScript
LEGO Universe - Three.js 3D Experience
Интерактивная 3D сцена с LEGO блоками, созданная с помощью Three.js
Живой предпросмотр
Ошибка рендеринга React компонента
Не удалось отобразить React компонент. Проверьте синтаксис.
Детали ошибки
Unexpected token '<'
Исходный код
import React, { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
export default function LegoExperience() {
const containerRef = useRef(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!containerRef.current) return;
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.fog = new THREE.Fog(0xffffff, 10, 50);
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 30;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
containerRef.current.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const directionalLight1 = new THREE.DirectionalLight(0xff3366, 1);
directionalLight1.position.set(5, 5, 5);
scene.add(directionalLight1);
const directionalLight2 = new THREE.DirectionalLight(0x3366ff, 0.8);
directionalLight2.position.set(-5, -5, 5);
scene.add(directionalLight2);
const pointLight = new THREE.PointLight(0xffaa00, 1, 50);
pointLight.position.set(0, 0, 10);
scene.add(pointLight);
// LEGO brick colors
const legoColors = [
0xff0000, // Red
0x0055ff, // Blue
0xffdd00, // Yellow
0x00aa00, // Green
0xff6600, // Orange
0xff00ff, // Magenta
0x00ffff, // Cyan
0xffffff, // White
];
// Create LEGO brick geometry
function createLegoBrick() {
const group = new THREE.Group();
// Main brick body
const bodyGeometry = new THREE.BoxGeometry(2, 1.2, 1);
const color = legoColors[Math.floor(Math.random() * legoColors.length)];
const bodyMaterial = new THREE.MeshStandardMaterial({
color: color,
metalness: 0.3,
roughness: 0.4,
emissive: color,
emissiveIntensity: 0.05,
});
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.castShadow = true;
group.add(body);
// Studs on top
const studGeometry = new THREE.CylinderGeometry(0.25, 0.25, 0.3, 16);
const studMaterial = new THREE.MeshStandardMaterial({
color: color,
metalness: 0.4,
roughness: 0.3,
emissive: color,
emissiveIntensity: 0.05,
});
// Create 2x4 stud pattern
for (let i = 0; i < 2; i++) {
for (let j = 0; j < 4; j++) {
const stud = new THREE.Mesh(studGeometry, studMaterial);
stud.position.set(-0.75 + j * 0.5, 0.75, -0.25 + i * 0.5);
group.add(stud);
}
}
return group;
}
// Create multiple LEGO bricks
const bricks = [];
const numBricks = 50;
for (let i = 0; i < numBricks; i++) {
const brick = createLegoBrick();
// Random position
brick.position.x = (Math.random() - 0.5) * 60;
brick.position.y = (Math.random() - 0.5) * 40;
brick.position.z = (Math.random() - 0.5) * 40;
// Random rotation
brick.rotation.x = Math.random() * Math.PI * 2;
brick.rotation.y = Math.random() * Math.PI * 2;
brick.rotation.z = Math.random() * Math.PI * 2;
// Random scale
const scale = 0.5 + Math.random() * 0.8;
brick.scale.set(scale, scale, scale);
// Store velocity for animation
brick.userData = {
velocityX: (Math.random() - 0.5) * 0.02,
velocityY: (Math.random() - 0.5) * 0.02,
velocityZ: (Math.random() - 0.5) * 0.02,
rotationSpeedX: (Math.random() - 0.5) * 0.02,
rotationSpeedY: (Math.random() - 0.5) * 0.02,
rotationSpeedZ: (Math.random() - 0.5) * 0.02,
};
scene.add(brick);
bricks.push(brick);
}
// Particle system for extra magic
const particlesGeometry = new THREE.BufferGeometry();
const particlesCount = 1000;
const posArray = new Float32Array(particlesCount * 3);
for (let i = 0; i < particlesCount * 3; i++) {
posArray[i] = (Math.random() - 0.5) * 100;
}
particlesGeometry.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
const particlesMaterial = new THREE.PointsMaterial({
size: 0.05,
color: 0x888888,
transparent: true,
opacity: 0.3,
blending: THREE.NormalBlending,
});
const particlesMesh = new THREE.Points(particlesGeometry, particlesMaterial);
scene.add(particlesMesh);
// Mouse interaction
const mouse = { x: 0, y: 0 };
const handleMouseMove = (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
};
window.addEventListener('mousemove', handleMouseMove);
// Animation
let time = 0;
function animate() {
requestAnimationFrame(animate);
time += 0.01;
// Animate LEGO bricks
bricks.forEach((brick, index) => {
// Floating motion
brick.position.x += brick.userData.velocityX;
brick.position.y += brick.userData.velocityY;
brick.position.z += brick.userData.velocityZ;
// Boundary check
if (Math.abs(brick.position.x) > 30) brick.userData.velocityX *= -1;
if (Math.abs(brick.position.y) > 20) brick.userData.velocityY *= -1;
if (Math.abs(brick.position.z) > 20) brick.userData.velocityZ *= -1;
// Rotation
brick.rotation.x += brick.userData.rotationSpeedX;
brick.rotation.y += brick.userData.rotationSpeedY;
brick.rotation.z += brick.userData.rotationSpeedZ;
// Wave effect
brick.position.y += Math.sin(time + index * 0.5) * 0.02;
// Mouse interaction
const dx = brick.position.x - mouse.x * 20;
const dy = brick.position.y - mouse.y * 20;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
brick.position.x += dx * 0.01;
brick.position.y += dy * 0.01;
}
});
// Rotate particle system
particlesMesh.rotation.y += 0.0005;
particlesMesh.rotation.x += 0.0003;
// Animate point light
pointLight.position.x = Math.sin(time * 0.5) * 15;
pointLight.position.y = Math.cos(time * 0.7) * 15;
// Camera gentle movement
camera.position.x = Math.sin(time * 0.2) * 2;
camera.position.y = Math.cos(time * 0.15) * 2;
camera.lookAt(0, 0, 0);
renderer.render(scene, camera);
}
animate();
setLoading(false);
// Handle window resize
const handleResize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
window.addEventListener('resize', handleResize);
// Cleanup
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('resize', handleResize);
if (containerRef.current) {
containerRef.current.removeChild(renderer.domElement);
}
renderer.dispose();
};
}, []);
return (
<div style={{ position: 'relative', width: '100vw', height: '100vh', overflow: 'hidden' }}>
{loading && (
<div
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
color: '#333',
fontSize: '24px',
fontFamily: 'Arial, sans-serif',
zIndex: 10,
}}
>
Загрузка...
</div>
)}
<div
style={{
position: 'absolute',
top: '20px',
left: '50%',
transform: 'translateX(-50%)',
color: '#333',
fontSize: '48px',
fontWeight: 'bold',
fontFamily: 'Arial, sans-serif',
textShadow: '0 0 20px rgba(0,0,0,0.1)',
zIndex: 5,
pointerEvents: 'none',
}}
>
LEGO Universe
</div>
<div
style={{
position: 'absolute',
bottom: '20px',
left: '50%',
transform: 'translateX(-50%)',
color: 'rgba(0,0,0,0.6)',
fontSize: '16px',
fontFamily: 'Arial, sans-serif',
zIndex: 5,
pointerEvents: 'none',
textAlign: 'center',
}}
>
Двигайте мышью для взаимодействия
</div>
<div ref={containerRef} />
</div>
);
}