From aa174c3fbabce969b4751304e8e262255709c736 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 19:08:33 +0000 Subject: [PATCH] Update src/app/gym-3d/page.tsx --- src/app/gym-3d/page.tsx | 514 +++++++++++++++++++++------------------- 1 file changed, 275 insertions(+), 239 deletions(-) diff --git a/src/app/gym-3d/page.tsx b/src/app/gym-3d/page.tsx index 30b1185..aba90f0 100644 --- a/src/app/gym-3d/page.tsx +++ b/src/app/gym-3d/page.tsx @@ -1,10 +1,12 @@ "use client"; -import { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import * as THREE from 'three'; import NavbarLayoutFloatingOverlay from '@/components/navbar/NavbarLayoutFloatingOverlay/NavbarLayoutFloatingOverlay'; import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; -import { ChevronDown, Mail, Phone, MapPin } from 'lucide-react'; +import { Zap } from 'lucide-react'; +import Input from '@/components/form/Input'; +import ButtonElasticEffect from '@/components/button/ButtonElasticEffect/ButtonElasticEffect'; interface FormData { name: string; @@ -14,9 +16,7 @@ interface FormData { } export default function Gym3DPage() { - const mountRef = useRef(null); - const sceneRef = useRef(null); - const rendererRef = useRef(null); + const canvasRef = useRef(null); const [formData, setFormData] = useState({ name: '', email: '', @@ -26,198 +26,247 @@ export default function Gym3DPage() { const [submitted, setSubmitted] = useState(false); useEffect(() => { - if (!mountRef.current) return; + if (!canvasRef.current) return; // Scene setup const scene = new THREE.Scene(); scene.background = new THREE.Color(0x0a0a0a); - sceneRef.current = scene; - - // Camera + const camera = new THREE.PerspectiveCamera( 75, - mountRef.current.clientWidth / mountRef.current.clientHeight, + canvasRef.current.clientWidth / canvasRef.current.clientHeight, 0.1, 1000 ); camera.position.set(0, 5, 15); - camera.lookAt(0, 5, 0); - // Renderer - const renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setSize(mountRef.current.clientWidth, mountRef.current.clientHeight); + 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.shadowMap.enabled = true; - renderer.shadowMap.type = THREE.PCFShadowMap; - mountRef.current.appendChild(renderer.domElement); - rendererRef.current = renderer; // Lighting const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); - const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + const directionalLight = new THREE.DirectionalLight(0xffff00, 1); directionalLight.position.set(10, 20, 10); directionalLight.castShadow = true; directionalLight.shadow.mapSize.width = 2048; directionalLight.shadow.mapSize.height = 2048; scene.add(directionalLight); - const pointLight = new THREE.PointLight(0xffff00, 0.5); - pointLight.position.set(0, 10, 0); + const pointLight = new THREE.PointLight(0xff6b00, 0.8); + pointLight.position.set(-10, 10, -10); scene.add(pointLight); - // Floor - const floorGeometry = new THREE.PlaneGeometry(50, 50); + // Gym floor + const floorGeometry = new THREE.PlaneGeometry(40, 40); const floorMaterial = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, roughness: 0.8, - metalness: 0.1 + metalness: 0.1, }); const floor = new THREE.Mesh(floorGeometry, floorMaterial); floor.rotation.x = -Math.PI / 2; - floor.castShadow = true; floor.receiveShadow = true; scene.add(floor); // Walls const wallMaterial = new THREE.MeshStandardMaterial({ - color: 0x2a2a2a, - roughness: 0.7, - metalness: 0.05 + color: 0x1a1a1a, + roughness: 0.9, }); - // Back wall - const backWallGeometry = new THREE.BoxGeometry(50, 15, 1); + const backWallGeometry = new THREE.PlaneGeometry(40, 20); const backWall = new THREE.Mesh(backWallGeometry, wallMaterial); - backWall.position.set(0, 7.5, -25); - backWall.castShadow = true; + backWall.position.z = -20; + backWall.position.y = 10; backWall.receiveShadow = true; scene.add(backWall); - // Side walls - const sideWallGeometry = new THREE.BoxGeometry(1, 15, 50); - const leftWall = new THREE.Mesh(sideWallGeometry, wallMaterial); - leftWall.position.set(-25, 7.5, 0); - leftWall.castShadow = true; + 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); - const rightWall = new THREE.Mesh(sideWallGeometry, wallMaterial); - rightWall.position.set(25, 7.5, 0); - rightWall.castShadow = true; - rightWall.receiveShadow = true; - scene.add(rightWall); + // 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, + }); - // Equipment - Barbells/Rack - const rackGeometry = new THREE.BoxGeometry(8, 2, 0.5); - const rackMaterial = new THREE.MeshStandardMaterial({ - color: 0x333333, - roughness: 0.3, - metalness: 0.8 - }); - const rack = new THREE.Mesh(rackGeometry, rackMaterial); - rack.position.set(-10, 1, 0); - rack.castShadow = true; - rack.receiveShadow = true; - scene.add(rack); + // 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 - for (let i = 0; i < 5; i++) { - const dumbbell = new THREE.Mesh( - new THREE.CylinderGeometry(0.3, 0.3, 0.8, 16), - new THREE.MeshStandardMaterial({ - color: 0xff6600, - roughness: 0.2, - metalness: 0.9 - }) - ); - dumbbell.position.set(-15 + i * 2, 0.5, -5); - dumbbell.castShadow = true; - dumbbell.receiveShadow = true; - scene.add(dumbbell); - } + 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); - // Rings (suspension trainer) - const ringGeometry = new THREE.TorusGeometry(0.3, 0.05, 16, 16); - const ringMaterial = new THREE.MeshStandardMaterial({ - color: 0xffff00, - roughness: 0.3, - metalness: 0.8 - }); - for (let i = 0; i < 2; i++) { - const ring = new THREE.Mesh(ringGeometry, ringMaterial); - ring.position.set(-5 + i * 10, 8, -10); - ring.castShadow = true; - ring.receiveShadow = true; - scene.add(ring); - } + 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); - // Climbing wall - const climbingWallGeometry = new THREE.BoxGeometry(8, 10, 0.3); - const climbingWallMaterial = new THREE.MeshStandardMaterial({ - color: 0x444444, - roughness: 0.8, - metalness: 0.1 - }); - const climbingWall = new THREE.Mesh(climbingWallGeometry, climbingWallMaterial); - climbingWall.position.set(10, 5, -22); - climbingWall.castShadow = true; - climbingWall.receiveShadow = true; - scene.add(climbingWall); + 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); - // Hold indicators on climbing wall - for (let i = 0; i < 6; i++) { - const hold = new THREE.Mesh( - new THREE.SphereGeometry(0.3, 16, 16), - new THREE.MeshStandardMaterial({ - color: 0xff3333, - roughness: 0.4, - metalness: 0.6 - }) - ); - hold.position.set( - 10 - 2 + (i % 3) * 2, - 5 + Math.floor(i / 3) * 3, - -21.5 - ); - hold.castShadow = true; - hold.receiveShadow = true; - scene.add(hold); - } + group.position.set(x, 0.5, z); + return group; + }; - // Treadmill/Cardio station - const treadmillGeometry = new THREE.BoxGeometry(1.5, 1, 2); - const treadmillMaterial = new THREE.MeshStandardMaterial({ - color: 0x1a1a1a, - roughness: 0.6, - metalness: 0.4 - }); - const treadmill = new THREE.Mesh(treadmillGeometry, treadmillMaterial); - treadmill.position.set(15, 0.5, 0); - treadmill.castShadow = true; - treadmill.receiveShadow = true; - scene.add(treadmill); + 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 animationId: number; + let animationFrameId: number; const animate = () => { - animationId = requestAnimationFrame(animate); + animationFrameId = requestAnimationFrame(animate); - // Rotate the camera around the scene - const angle = Date.now() * 0.0001; - camera.position.x = Math.sin(angle) * 20; - camera.position.z = Math.cos(angle) * 20; - camera.lookAt(0, 5, 0); + // Rotate scene slightly + scene.rotation.y += 0.0003; renderer.render(scene, camera); }; + animate(); - // Handle resize + // Handle window resize const handleResize = () => { - if (!mountRef.current) return; - const width = mountRef.current.clientWidth; - const height = mountRef.current.clientHeight; + if (!canvasRef.current) return; + const width = canvasRef.current.clientWidth; + const height = canvasRef.current.clientHeight; camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setSize(width, height); @@ -227,28 +276,24 @@ export default function Gym3DPage() { return () => { window.removeEventListener('resize', handleResize); - cancelAnimationFrame(animationId); - mountRef.current?.removeChild(renderer.domElement); + cancelAnimationFrame(animationFrameId); + renderer.dispose(); }; }, []); - const handleInputChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; + const handleInputChange = (field: keyof FormData, value: string) => { setFormData(prev => ({ ...prev, - [name]: value + [field]: value })); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - // Handle form submission console.log('Form submitted:', formData); setSubmitted(true); - setTimeout(() => { - setSubmitted(false); - setFormData({ name: '', email: '', phone: '', message: '' }); - }, 3000); + setFormData({ name: '', email: '', phone: '', message: '' }); + setTimeout(() => setSubmitted(false), 3000); }; return ( @@ -272,114 +317,105 @@ export default function Gym3DPage() { { name: "Pricing", id: "pricing" }, { name: "Gallery", id: "gallery" }, { name: "Testimonials", id: "testimonials" }, - { name: "Home", id: "/" } + { name: "3D Gym", id: "gym-3d" }, + { name: "Contact", id: "contact" } ]} button={{ text: "Start Your Trial", href: "contact" }} /> -
- {/* 3D Gym Visualization */} -
+
+ {/* 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.

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

Contact Us

-

Interested in our 3D gym experience or want to learn more? Get in touch!

+
+
+
+

+ + Contattaci +

+

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

+
- {submitted ? ( -
-

✓ Thank you for reaching out!

-

We'll get back to you soon.

+
+
+ + 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" + /> +
-
- -