diff --git a/src/pages/index.astro b/src/pages/index.astro index a25b02d..dcce124 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -221,9 +221,10 @@ const process = [
+
-
+
@@ -232,40 +233,34 @@ const process = [
-
+
- Marketing - เพิ่มรายได้ + Marketing + เพิ่มรายได้
-
+
- AI - ลดต้นทุนและเวลา + AI + ลดต้นทุนและเวลา
-
+
- Business Knowledge - ลดความเสี่ยง + Business Knowledge + ลดความเสี่ยง
- - -
+
diff --git a/src/scripts/home.js b/src/scripts/home.js index 27e1a37..eed3186 100644 --- a/src/scripts/home.js +++ b/src/scripts/home.js @@ -180,53 +180,138 @@ form?.addEventListener('submit', async (event) => { } }); -// Neural Network Hero - Mouse Parallax -const neuralScene = document.querySelector('.neural-scene'); +// Neural Network Hero - True 3D with Dynamic Lines const heroNeural = document.querySelector('.hero-neural'); +const neuralScene = document.querySelector('.neural-scene'); +const canvas = document.querySelector('.neural-canvas'); +const ctx = canvas?.getContext('2d'); +const nodes = document.querySelectorAll('.neural-node'); -if (neuralScene && heroNeural) { +if (heroNeural && neuralScene && canvas && ctx && nodes.length > 0) { + // 3D rotation state let targetRotateX = 0; let targetRotateY = 0; let currentRotateX = 0; let currentRotateY = 0; + // Canvas setup + function resizeCanvas() { + const rect = heroNeural.getBoundingClientRect(); + canvas.width = rect.width * window.devicePixelRatio; + canvas.height = rect.height * window.devicePixelRatio; + canvas.style.width = rect.width + 'px'; + canvas.style.height = rect.height + 'px'; + ctx.scale(window.devicePixelRatio, window.devicePixelRatio); + } + + resizeCanvas(); + window.addEventListener('resize', resizeCanvas); + + // Find intersection point on node border + function findBorderPoint(nodeRect, targetX, targetY) { + const cx = nodeRect.left + nodeRect.width / 2; + const cy = nodeRect.top + nodeRect.height / 2; + const hw = nodeRect.width / 2; + const hh = nodeRect.height / 2; + + const dx = targetX - cx; + const dy = targetY - cy; + + if (dx === 0 && dy === 0) return { x: cx, y: cy }; + + const absDx = Math.abs(dx); + const absDy = Math.abs(dy); + + let scale; + if (absDx * hh > absDy * hw) { + scale = hw / absDx; + } else { + scale = hh / absDy; + } + + return { + x: cx + dx * scale, + y: cy + dy * scale + }; + } + + // Draw connections + function drawConnections() { + const rect = heroNeural.getBoundingClientRect(); + ctx.clearRect(0, 0, rect.width, rect.height); + + const centerNode = document.querySelector('[data-node="center"]'); + const outerNodes = document.querySelectorAll('.neural-card'); + + if (!centerNode) return; + + const centerRect = centerNode.getBoundingClientRect(); + const centerX = centerRect.left + centerRect.width / 2 - rect.left; + const centerY = centerRect.top + centerRect.height / 2 - rect.top; + + outerNodes.forEach(node => { + const nodeRect = node.getBoundingClientRect(); + const nodeX = nodeRect.left + nodeRect.width / 2 - rect.left; + const nodeY = nodeRect.top + nodeRect.height / 2 - rect.top; + + const startPt = findBorderPoint( + { left: centerRect.left - rect.left, top: centerRect.top - rect.top, + width: centerRect.width, height: centerRect.height }, + nodeX, nodeY + ); + + const endPt = findBorderPoint( + { left: nodeRect.left - rect.left, top: nodeRect.top - rect.top, + width: nodeRect.width, height: nodeRect.height }, + centerX, centerY + ); + + ctx.beginPath(); + ctx.moveTo(startPt.x, startPt.y); + ctx.lineTo(endPt.x, endPt.y); + ctx.strokeStyle = 'rgba(254, 212, 0, 0.5)'; + ctx.lineWidth = 3; + ctx.lineCap = 'round'; + ctx.stroke(); + }); + } + // Mouse move handler heroNeural.addEventListener('mousemove', (e) => { const rect = heroNeural.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width; const y = (e.clientY - rect.top) / rect.height; - // Convert to rotation angles (±15 degrees) - targetRotateY = (x - 0.5) * 30; // -15 to +15 - targetRotateX = (y - 0.5) * -30; // -15 to +15 (inverted) + targetRotateY = (x - 0.5) * 30; + targetRotateX = (y - 0.5) * -30; }); - // Reset on mouse leave heroNeural.addEventListener('mouseleave', () => { targetRotateX = 0; targetRotateY = 0; }); - // Smooth animation loop + // Animation loop function animate() { - // Ease towards target currentRotateX += (targetRotateX - currentRotateX) * 0.08; currentRotateY += (targetRotateY - currentRotateY) * 0.08; neuralScene.style.transform = `rotateX(${currentRotateX}deg) rotateY(${currentRotateY}deg)`; + drawConnections(); + requestAnimationFrame(animate); } animate(); - // Mobile: Device orientation (if available) + // Mobile: Device orientation if (window.DeviceOrientationEvent && 'ontouchstart' in window) { window.addEventListener('deviceorientation', (e) => { if (e.gamma !== null && e.beta !== null) { - targetRotateY = e.gamma * 0.3; // -30 to +30 scaled down - targetRotateX = (e.beta - 45) * 0.3; // Assume holding at 45deg + targetRotateY = e.gamma * 0.3; + targetRotateX = (e.beta - 45) * 0.3; } }); } diff --git a/src/styles/global.css b/src/styles/global.css index 4c5e938..e4abb98 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -448,44 +448,50 @@ background: rgb(255 255 255 / .10); color: rgb(255 255 255 / .72); } -/* Neural Network Hero - 3D Layout */ +/* Neural Network Hero - True 3D Layout */ .hero-neural { position: relative; width: 100%; - max-width: 480px; - height: 400px; + max-width: 560px; + height: 480px; margin-inline: auto; perspective: 1200px; } +.neural-canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 5; +} + .neural-scene { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; - transition: transform 0.1s ease-out; + transition: transform 0.15s ease-out; will-change: transform; } -/* Neural nodes */ +/* Neural nodes - base */ .neural-node { position: absolute; - border-radius: 20px; - padding: 20px 24px; + border-radius: 24px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; - min-width: 120px; transition: transform 0.3s ease, box-shadow 0.3s ease; cursor: default; backface-visibility: hidden; } .neural-node:hover { - transform: scale(1.05) translateZ(20px); - box-shadow: 0 20px 50px rgb(0 0 0 / .15); + box-shadow: 0 24px 60px rgb(0 0 0 / .18); } /* Center node: กำไร */ @@ -493,13 +499,15 @@ color: rgb(255 255 255 / .72); left: 50%; top: 50%; transform: translate(-50%, -50%) translateZ(0px); - min-width: 160px; - padding: 28px 32px; - border: 2px solid var(--yellow); + width: 180px; + height: 180px; + border-radius: 50%; + padding: 32px; + border: 3px solid var(--yellow); box-shadow: - 0 0 0 8px rgb(254 212 0 / .10), - 0 30px 80px rgb(254 212 0 / .18), - 0 10px 30px rgb(0 0 0 / .10); + 0 0 0 10px rgb(254 212 0 / .12), + 0 30px 80px rgb(254 212 0 / .20), + 0 10px 30px rgb(0 0 0 / .12); z-index: 10; } @@ -508,7 +516,7 @@ color: rgb(255 255 255 / .72); } .node-label { - font-size: clamp(2.4rem, 5vw, 3.2rem); + font-size: clamp(2.6rem, 5vw, 3.4rem); font-weight: 900; color: var(--ink); line-height: 1; @@ -516,66 +524,132 @@ color: rgb(255 255 255 / .72); } .node-sub { - margin-top: 8px; - font-size: 13px; + margin-top: 10px; + font-size: 14px; font-weight: 600; color: var(--muted); line-height: 1.4; } -/* Outer nodes */ +/* Outer cards - larger and positioned in 3D */ +.neural-card { + width: 200px; + padding: 28px 24px; + min-height: 120px; +} + +/* True 3D positions: translate3d(x, y, z) */ .node-marketing { - left: 12%; - top: 15%; - transform: translateZ(-150px); + left: 50%; + top: 50%; + transform: translate(-50%, -50%) translate3d(-280px, -160px, -180px); } .node-ai { - left: 68%; - top: 30%; - transform: translateZ(-100px); + left: 50%; + top: 50%; + transform: translate(-50%, -50%) translate3d(240px, 80px, -120px); } .node-biz { - left: 25%; - top: 65%; - transform: translateZ(-200px); + left: 50%; + top: 50%; + transform: translate(-50%, -50%) translate3d(-160px, 200px, -250px); } -.node-tag { - font-size: 15px; +.card-tag { + font-size: 16px; font-weight: 900; color: var(--ink); letter-spacing: .02em; text-transform: uppercase; } -.node-desc { - margin-top: 6px; - font-size: 13px; +.card-desc { + margin-top: 8px; + font-size: 14px; font-weight: 500; color: var(--muted); line-height: 1.4; } -/* Neural connections */ -.neural-connections { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: 5; - transform-style: preserve-3d; +/* Floating animations */ +.node-marketing { + animation: float-1 6s ease-in-out infinite; } -.neural-line { - animation: pulse-line 3s ease-in-out infinite; +.node-ai { + animation: float-2 7s ease-in-out infinite; } -@keyframes pulse-line { - 0%, 100% { opacity: .3; } - 50% { opacity: .6; } +.node-biz { + animation: float-3 8s ease-in-out infinite; +} + +@keyframes float-1 { + 0%, 100% { transform: translate(-50%, -50%) translate3d(-280px, -160px, -180px); } + 50% { transform: translate(-50%, -50%) translate3d(-280px, -175px, -180px); } +} + +@keyframes float-2 { + 0%, 100% { transform: translate(-50%, -50%) translate3d(240px, 80px, -120px); } + 50% { transform: translate(-50%, -50%) translate3d(240px, 65px, -120px); } +} + +@keyframes float-3 { + 0%, 100% { transform: translate(-50%, -50%) translate3d(-160px, 200px, -250px); } + 50% { transform: translate(-50%, -50%) translate3d(-160px, 185px, -250px); } +} + +/* Mobile responsive */ +@media (max-width: 620px) { + .hero-neural { + height: auto; + max-width: 340px; + perspective: none; + } + + .neural-canvas { + display: none; + } + + .neural-scene { + display: flex; + flex-direction: column; + align-items: center; + gap: 24px; + transform: none !important; + padding: 20px 0; + } + + .neural-node { + position: relative; + left: auto !important; + top: auto !important; + transform: none !important; + } + + .node-center { + width: 160px; + height: 160px; + } + + .neural-card { + width: 100%; + max-width: 280px; + min-height: auto; + } + + .neural-node:hover { + transform: translateY(-4px); + } + + @keyframes float-1, + @keyframes float-2, + @keyframes float-3 { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-8px); } + } } /* Floating animation for nodes */