From 39736cb05da722a58b584195ead0e717cf054e8a Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 19:28:10 +0000 Subject: [PATCH 1/3] Update src/app/gym-3d/page.tsx --- src/app/gym-3d/page.tsx | 520 ++++++++++++++-------------------------- 1 file changed, 182 insertions(+), 338 deletions(-) diff --git a/src/app/gym-3d/page.tsx b/src/app/gym-3d/page.tsx index aba90f0..edb3890 100644 --- a/src/app/gym-3d/page.tsx +++ b/src/app/gym-3d/page.tsx @@ -1,301 +1,208 @@ "use client"; -import React, { useEffect, useRef, useState } from 'react'; -import * as THREE from 'three'; +import { useEffect, useRef, useState } from "react"; +import * as THREE from "three"; import NavbarLayoutFloatingOverlay from '@/components/navbar/NavbarLayoutFloatingOverlay/NavbarLayoutFloatingOverlay'; +import ContactSplitForm from '@/components/sections/contact/ContactSplitForm'; import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; -import { Zap } from 'lucide-react'; -import Input from '@/components/form/Input'; -import ButtonElasticEffect from '@/components/button/ButtonElasticEffect/ButtonElasticEffect'; - -interface FormData { - name: string; - email: string; - phone: string; - message: string; -} +import { Phone } from "lucide-react"; export default function Gym3DPage() { - const canvasRef = useRef(null); - const [formData, setFormData] = useState({ - name: '', - email: '', - phone: '', - message: '' - }); - const [submitted, setSubmitted] = useState(false); + const containerRef = useRef(null); + const sceneRef = useRef(null); + const cameraRef = useRef(null); + const rendererRef = useRef(null); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { - if (!canvasRef.current) return; + if (!containerRef.current) return; // Scene setup const scene = new THREE.Scene(); scene.background = new THREE.Color(0x0a0a0a); - + sceneRef.current = scene; + + // Camera setup const camera = new THREE.PerspectiveCamera( 75, - canvasRef.current.clientWidth / canvasRef.current.clientHeight, + containerRef.current.clientWidth / containerRef.current.clientHeight, 0.1, 1000 ); - camera.position.set(0, 5, 15); + camera.position.set(0, 10, 20); + camera.lookAt(0, 5, 0); + cameraRef.current = camera; - const renderer = new THREE.WebGLRenderer({ - canvas: canvasRef.current, - antialias: true, - alpha: true, - }); - renderer.setSize(canvasRef.current.clientWidth, canvasRef.current.clientHeight); - renderer.setPixelRatio(window.devicePixelRatio); + // Renderer setup + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight); renderer.shadowMap.enabled = true; + containerRef.current.appendChild(renderer.domElement); + rendererRef.current = renderer; // Lighting const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); - const directionalLight = new THREE.DirectionalLight(0xffff00, 1); - directionalLight.position.set(10, 20, 10); + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + directionalLight.position.set(10, 15, 10); directionalLight.castShadow = true; directionalLight.shadow.mapSize.width = 2048; directionalLight.shadow.mapSize.height = 2048; scene.add(directionalLight); - const pointLight = new THREE.PointLight(0xff6b00, 0.8); - pointLight.position.set(-10, 10, -10); - scene.add(pointLight); + // Ground/Floor + const groundGeometry = new THREE.PlaneGeometry(40, 40); + const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x1a1a1a }); + const ground = new THREE.Mesh(groundGeometry, groundMaterial); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); - // Gym floor - const floorGeometry = new THREE.PlaneGeometry(40, 40); - const floorMaterial = new THREE.MeshStandardMaterial({ - color: 0x1a1a1a, - roughness: 0.8, - metalness: 0.1, + // Gym Equipment - Power Rack + const rackGeometry = new THREE.BoxGeometry(2, 3, 1.5); + const rackMaterial = new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.8 }); + const rack = new THREE.Mesh(rackGeometry, rackMaterial); + rack.position.set(-8, 1.5, 0); + rack.castShadow = true; + scene.add(rack); + + // Barbell + const barbellGeometry = new THREE.CylinderGeometry(0.02, 0.02, 2.2, 16); + const barbellMaterial = new THREE.MeshStandardMaterial({ color: 0xffff00, metalness: 1 }); + const barbell = new THREE.Mesh(barbellGeometry, barbellMaterial); + barbell.position.set(-8, 1.8, 0); + barbell.rotation.z = Math.PI / 2; + barbell.castShadow = true; + scene.add(barbell); + + // Weight plates on barbell + for (let i = 0; i < 4; i++) { + const plateGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.05, 32); + const plateMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000, metalness: 0.6 }); + const plate = new THREE.Mesh(plateGeometry, plateMaterial); + plate.position.set(-8 + (i - 1.5) * 0.6, 1.8, 0); + plate.castShadow = true; + scene.add(plate); + } + + // Dumbbells rack + for (let i = 0; i < 5; i++) { + const dumbellGeometry = new THREE.CylinderGeometry(0.15, 0.15, 0.5, 16); + const dumbellMaterial = new THREE.MeshStandardMaterial({ color: 0xffaa00, metalness: 0.7 }); + const dumbell = new THREE.Mesh(dumbellGeometry, dumbellMaterial); + dumbell.position.set(0 + i * 1.5, 0.5, -10); + dumbell.castShadow = true; + scene.add(dumbell); + } + + // Gymnastics Rig + const rigGeometry = new THREE.BoxGeometry(0.1, 0.1, 5); + const rigMaterial = new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.8 }); + const rig = new THREE.Mesh(rigGeometry, rigMaterial); + rig.position.set(0, 8, 0); + rig.castShadow = true; + scene.add(rig); + + // Olympic Rings + const ringRadius = 0.3; + const ringPositions = [-1.2, -0.4, 0.4, 1.2]; + ringPositions.forEach((x) => { + const torusGeometry = new THREE.TorusGeometry(ringRadius, 0.08, 16, 100); + const torusMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff, metalness: 0.9 }); + const ring = new THREE.Mesh(torusGeometry, torusMaterial); + ring.position.set(x, 7, 0); + ring.rotation.x = Math.PI / 5; + ring.castShadow = true; + scene.add(ring); }); - const floor = new THREE.Mesh(floorGeometry, floorMaterial); - floor.rotation.x = -Math.PI / 2; - floor.receiveShadow = true; - scene.add(floor); + + // Rowing Machine + const rowingGeometry = new THREE.BoxGeometry(0.8, 1, 2.5); + const rowingMaterial = new THREE.MeshStandardMaterial({ color: 0x222222, metalness: 0.6 }); + const rowingMachine = new THREE.Mesh(rowingGeometry, rowingMaterial); + rowingMachine.position.set(8, 0.8, -5); + rowingMachine.castShadow = true; + scene.add(rowingMachine); + + // Treadmill + const treadmillGeometry = new THREE.BoxGeometry(1, 1.2, 2); + const treadmillMaterial = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, metalness: 0.5 }); + const treadmill = new THREE.Mesh(treadmillGeometry, treadmillMaterial); + treadmill.position.set(8, 0.8, 0); + treadmill.castShadow = true; + scene.add(treadmill); + + // Kettlebells + for (let i = 0; i < 3; i++) { + const kettlebellGeometry = new THREE.SphereGeometry(0.4, 16, 16); + const kettlebellMaterial = new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.7 }); + const kettlebell = new THREE.Mesh(kettlebellGeometry, kettlebellMaterial); + kettlebell.position.set(-10, 0.6, -5 + i * 2); + kettlebell.castShadow = true; + scene.add(kettlebell); + } + + // Battle Ropes anchor + const ropeAnchorGeometry = new THREE.BoxGeometry(0.2, 3, 0.2); + const ropeAnchorMaterial = new THREE.MeshStandardMaterial({ color: 0x444444, metalness: 0.8 }); + const ropeAnchor = new THREE.Mesh(ropeAnchorGeometry, ropeAnchorMaterial); + ropeAnchor.position.set(0, 2, 10); + ropeAnchor.castShadow = true; + scene.add(ropeAnchor); // Walls - const wallMaterial = new THREE.MeshStandardMaterial({ - color: 0x1a1a1a, - roughness: 0.9, - }); + const wallGeometry = new THREE.BoxGeometry(40, 5, 0.5); + const wallMaterial = new THREE.MeshStandardMaterial({ color: 0x0f0f0f }); + + const wallBack = new THREE.Mesh(wallGeometry, wallMaterial); + wallBack.position.set(0, 2.5, -20); + wallBack.receiveShadow = true; + scene.add(wallBack); - const backWallGeometry = new THREE.PlaneGeometry(40, 20); - const backWall = new THREE.Mesh(backWallGeometry, wallMaterial); - backWall.position.z = -20; - backWall.position.y = 10; - backWall.receiveShadow = true; - scene.add(backWall); + // Loading complete + setIsLoading(false); - const leftWallGeometry = new THREE.PlaneGeometry(40, 20); - const leftWall = new THREE.Mesh(leftWallGeometry, wallMaterial); - leftWall.rotation.y = Math.PI / 2; - leftWall.position.x = -20; - leftWall.position.y = 10; - leftWall.receiveShadow = true; - scene.add(leftWall); - - // Power racks - const createPowerRack = (x: number, z: number) => { - const rackGroup = new THREE.Group(); - - const tubeMaterial = new THREE.MeshStandardMaterial({ - color: 0x333333, - metalness: 0.7, - roughness: 0.3, - }); - - // Vertical posts - const postGeometry = new THREE.BoxGeometry(0.1, 3, 0.1); - for (let i = 0; i < 4; i++) { - const post = new THREE.Mesh(postGeometry, tubeMaterial); - const offsetX = i % 2 === 0 ? -0.5 : 0.5; - const offsetZ = i < 2 ? -0.5 : 0.5; - post.position.set(offsetX, 1.5, offsetZ); - post.castShadow = true; - post.receiveShadow = true; - rackGroup.add(post); - } - - // Horizontal bars - const barGeometry = new THREE.BoxGeometry(1.2, 0.08, 1.2); - const bar = new THREE.Mesh(barGeometry, tubeMaterial); - bar.position.y = 2.5; - bar.castShadow = true; - bar.receiveShadow = true; - rackGroup.add(bar); - - rackGroup.position.set(x, 0, z); - return rackGroup; - }; - - scene.add(createPowerRack(-8, -5)); - scene.add(createPowerRack(8, -5)); - scene.add(createPowerRack(-8, 5)); - scene.add(createPowerRack(8, 5)); - - // Dumbbells - const createDumbbell = (x: number, z: number) => { - const group = new THREE.Group(); - const handleMaterial = new THREE.MeshStandardMaterial({ - color: 0xffff00, - metalness: 0.8, - roughness: 0.2, - }); - - const handle = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.3), handleMaterial); - handle.castShadow = true; - handle.receiveShadow = true; - group.add(handle); - - const weightMaterial = new THREE.MeshStandardMaterial({ - color: 0xff6b00, - metalness: 0.9, - roughness: 0.1, - }); - - const weight1 = new THREE.Mesh(new THREE.SphereGeometry(0.15, 16, 16), weightMaterial); - weight1.position.z = 0.2; - weight1.castShadow = true; - weight1.receiveShadow = true; - group.add(weight1); - - const weight2 = new THREE.Mesh(new THREE.SphereGeometry(0.15, 16, 16), weightMaterial); - weight2.position.z = -0.2; - weight2.castShadow = true; - weight2.receiveShadow = true; - group.add(weight2); - - group.position.set(x, 0.5, z); - return group; - }; - - scene.add(createDumbbell(-12, 0)); - scene.add(createDumbbell(-10, 0)); - scene.add(createDumbbell(10, 0)); - scene.add(createDumbbell(12, 0)); - - // Barbells on stands - const createBarbell = (x: number, z: number) => { - const group = new THREE.Group(); - - const barMaterial = new THREE.MeshStandardMaterial({ - color: 0xffff00, - metalness: 0.9, - roughness: 0.1, - }); - - const bar = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 2), barMaterial); - bar.rotation.z = Math.PI / 2; - bar.castShadow = true; - bar.receiveShadow = true; - group.add(bar); - - const plateMaterial = new THREE.MeshStandardMaterial({ - color: 0xff0000, - metalness: 0.7, - roughness: 0.3, - }); - - for (let i = 0; i < 4; i++) { - const plate = new THREE.Mesh(new THREE.CylinderGeometry(0.35, 0.35, 0.05), plateMaterial); - plate.position.z = (i - 1.5) * 0.2; - plate.rotation.z = Math.PI / 2; - plate.castShadow = true; - plate.receiveShadow = true; - group.add(plate); - } - - group.position.set(x, 1, z); - return group; - }; - - scene.add(createBarbell(0, -8)); - scene.add(createBarbell(0, 8)); - - // Rowing machines - const createRowingMachine = (x: number, z: number) => { - const group = new THREE.Group(); - - const frameMaterial = new THREE.MeshStandardMaterial({ - color: 0x333333, - metalness: 0.6, - roughness: 0.4, - }); - - const base = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.2, 2), frameMaterial); - base.castShadow = true; - base.receiveShadow = true; - group.add(base); - - const seat = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.3, 0.4), frameMaterial); - seat.position.set(0, 0.5, -0.3); - seat.castShadow = true; - seat.receiveShadow = true; - group.add(seat); - - const handle = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.1, 0.1), frameMaterial); - handle.position.set(0, 0.7, 0.6); - handle.castShadow = true; - handle.receiveShadow = true; - group.add(handle); - - group.position.set(x, 0, z); - return group; - }; - - scene.add(createRowingMachine(-5, 12)); - scene.add(createRowingMachine(5, 12)); - - // Animation - let animationFrameId: number; + // Animation loop const animate = () => { - animationFrameId = requestAnimationFrame(animate); + requestAnimationFrame(animate); - // Rotate scene slightly - scene.rotation.y += 0.0003; + // Rotate dumbbells slightly + scene.children.forEach((child) => { + if (child instanceof THREE.Mesh && child.geometry instanceof THREE.CylinderGeometry) { + if (child.position.z === -10) { + child.rotation.x += 0.01; + } + } + }); + + // Rotate camera slightly + const time = Date.now() * 0.0005; + camera.position.x = Math.sin(time) * 25; + camera.position.z = Math.cos(time) * 25; + camera.lookAt(0, 5, 0); renderer.render(scene, camera); }; - animate(); // Handle window resize const handleResize = () => { - if (!canvasRef.current) return; - const width = canvasRef.current.clientWidth; - const height = canvasRef.current.clientHeight; + if (!containerRef.current) return; + const width = containerRef.current.clientWidth; + const height = containerRef.current.clientHeight; camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setSize(width, height); }; - - window.addEventListener('resize', handleResize); + window.addEventListener("resize", handleResize); return () => { - window.removeEventListener('resize', handleResize); - cancelAnimationFrame(animationFrameId); - renderer.dispose(); + window.removeEventListener("resize", handleResize); + containerRef.current?.removeChild(renderer.domElement); }; }, []); - const handleInputChange = (field: keyof FormData, value: string) => { - setFormData(prev => ({ - ...prev, - [field]: value - })); - }; - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - console.log('Form submitted:', formData); - setSubmitted(true); - setFormData({ name: '', email: '', phone: '', message: '' }); - setTimeout(() => setSubmitted(false), 3000); - }; - return ( -
- {/* 3D Gym Viewer */} -
-
-
-

Tour Our 3D Gym

-

Explore Iron Pulse's state-of-the-art facility

-

Use your mouse to rotate and explore. Scroll to zoom.

-
- -
- +
+ {isLoading && ( +
+
+
+

Loading 3D Gym Tour...

-
+ )} +
- {/* Contact Form */} -
-
-
-

- - Contattaci -

-

Siamo pronti a rispondere a tutte le tue domande sulla nostra palestra 3D e i nostri servizi

-
- -
-
- - handleInputChange('name', value)} - type="text" - placeholder="Il tuo nome" - required - className="w-full" - /> -
- -
- - handleInputChange('email', value)} - type="email" - placeholder="La tua email" - required - className="w-full" - /> -
- -
- - handleInputChange('phone', value)} - type="tel" - placeholder="Il tuo numero di telefono" - className="w-full" - /> -
- -
- -