Institutional-grade protocols built for the next generation of healthcare.
+
+
+
+ {[
+ { icon: Lock, title: "Zero-Trust Protocol", desc: "Institutional-grade multi-layer security for clinical data transfers." },
+ { icon: MessageSquare, title: "Clinical AI Bridge", desc: "Real-time verification and documentation via medical LLM layers." },
+ { icon: Bell, title: "Predictive SOS Audit", desc: "Automated institutional alerts based on verified vital trend analysis." },
+ { icon: Globe, title: "Universal Sync Hub", desc: "Global access to clinical data on certified HIPAA infrastructure." },
+ { icon: Fingerprint, title: "Biometric Audit", desc: "Hardware-locked PHI access ensures zero-bias clinical security." },
+ { icon: ShieldCheck, title: "Institutional Verified", desc: "Certified infrastructure for sovereign clinical data integrity." }
+ ].map((feature, i) => (
+
+ {/* Hover Glow */}
+
+
+
+
+
+
+
+
+
{feature.title}
+
+ {feature.desc}
+
+
+
+
+ ))}
+
+
- );
-}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/canvas/BioNeurons.tsx b/app/components/canvas/BioNeurons.tsx
new file mode 100644
index 0000000..8592943
--- /dev/null
+++ b/app/components/canvas/BioNeurons.tsx
@@ -0,0 +1,192 @@
+"use client";
+
+import { useMemo, useRef, useState } from "react";
+import { Canvas, useFrame, useThree } from "@react-three/fiber";
+import { MeshDistortMaterial, Sphere, Preload, Float } from "@react-three/drei";
+import * as THREE from "three";
+
+// --- CONFIGURATION ---
+const NEURON_COUNT = 18; // Fewer, but more detailed neurons
+const CONNECTION_DISTANCE = 5.5; // Distance to form a synapse
+const PULSE_SPEED = 2.5; // Speed of the electric signal
+
+// 1. SINGLE NEURON CELL (The Soma)
+// We use a distorted sphere to make it look like organic tissue
+function NeuronCell({ position }: { position: [number, number, number] }) {
+ const meshRef = useRef(null!);
+ const [hovered, setHover] = useState(false);
+
+ // Randomize size slightly for variety
+ const scale = useMemo(() => 0.6 + Math.random() * 0.4, []);
+
+ useFrame((state) => {
+ // Gentle heartbeat pulsation
+ const t = state.clock.getElapsedTime();
+ const pulse = Math.sin(t * 3) * 0.05 + 1;
+ if (meshRef.current) {
+ meshRef.current.scale.set(scale * pulse, scale * pulse, scale * pulse);
+ }
+ });
+
+ return (
+
+ setHover(true)}
+ onPointerOut={() => setHover(false)}
+ >
+
+
+
+
+ );
+}
+
+// 2. SYNAPSE (The Connection & The Impulse)
+// Draws a curved organic line and a traveling light pulse
+function Synapse({ start, end }: { start: THREE.Vector3; end: THREE.Vector3 }) {
+ const curve = useMemo(() => {
+ // Create a quadratic bezier curve for a natural "tendon" look
+ // Control point is midway but offset randomly to create the curve
+ const mid = new THREE.Vector3().lerpVectors(start, end, 0.5);
+ mid.x += (Math.random() - 0.5) * 2;
+ mid.y += (Math.random() - 0.5) * 2;
+ mid.z += (Math.random() - 0.5) * 2;
+ return new THREE.QuadraticBezierCurve3(start, mid, end);
+ }, [start, end]);
+
+ // Create points for the line geometry
+ const points = useMemo(() => curve.getPoints(20), [curve]);
+
+ // The traveling impulse ref
+ const impulseRef = useRef(null!);
+
+ useFrame((state) => {
+ // Move the impulse along the curve
+ const t = (state.clock.getElapsedTime() * PULSE_SPEED) % 1; // 0 to 1 loop
+ if (impulseRef.current) {
+ const pos = curve.getPointAt(t);
+ impulseRef.current.position.copy(pos);
+
+ // Scale impulse based on position (fade in/out at ends)
+ const scale = Math.sin(t * Math.PI);
+ impulseRef.current.scale.setScalar(scale * 0.15);
+ }
+ });
+
+ return (
+
+ {/* The Axon (Line) */}
+
+
+ [p.x, p.y, p.z]))}
+ itemSize={3}
+ />
+
+
+
+
+ {/* The Electric Impulse (Glowing Dot) */}
+
+
+
+
+
+
+ );
+}
+
+// 3. MAIN SCENE CONTROLLER
+function NeuralNetworkScene() {
+ const { viewport } = useThree();
+ const mouse = useRef(new THREE.Vector2());
+
+ // Generate Neurons
+ const neurons = useMemo(() => {
+ const temp = [];
+ for (let i = 0; i < NEURON_COUNT; i++) {
+ temp.push({
+ position: new THREE.Vector3(
+ (Math.random() - 0.5) * 20,
+ (Math.random() - 0.5) * 20,
+ (Math.random() - 0.5) * 10
+ ),
+ id: i,
+ });
+ }
+ return temp;
+ }, []);
+
+ // Generate Connections (Proximity based)
+ const connections = useMemo(() => {
+ const conns = [];
+ for (let i = 0; i < neurons.length; i++) {
+ for (let j = i + 1; j < neurons.length; j++) {
+ const dist = neurons[i].position.distanceTo(neurons[j].position);
+ if (dist < CONNECTION_DISTANCE) {
+ conns.push({ start: neurons[i].position, end: neurons[j].position, key: `${i}-${j}` });
+ }
+ }
+ }
+ return conns;
+ }, [neurons]);
+
+ useFrame((state) => {
+ // Soft camera movement based on mouse
+ const x = (state.pointer.x * viewport.width) / 10;
+ const y = (state.pointer.y * viewport.height) / 10;
+
+ state.camera.position.x = THREE.MathUtils.lerp(state.camera.position.x, x, 0.05);
+ state.camera.position.y = THREE.MathUtils.lerp(state.camera.position.y, y, 0.05);
+ state.camera.lookAt(0, 0, 0);
+ });
+
+ return (
+
+ {/* Draw Neurons */}
+ {neurons.map((n) => (
+
+ ))}
+
+ {/* Draw Synapses */}
+ {connections.map((c) => (
+
+ ))}
+
+ );
+}
+
+export default function BioNeurons() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/canvas/DNAHelix.tsx b/app/components/canvas/DNAHelix.tsx
new file mode 100644
index 0000000..adf812b
--- /dev/null
+++ b/app/components/canvas/DNAHelix.tsx
@@ -0,0 +1,110 @@
+"use client";
+
+import React, { useEffect, useRef } from "react";
+
+interface Props {
+ className?: string;
+}
+
+const DNAHelix: React.FC = ({ className }) => {
+ const canvasRef = useRef(null);
+
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return;
+
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return;
+
+ // Dimensions based on parent container
+ let width = canvas.width = canvas.parentElement?.clientWidth || window.innerWidth;
+ let height = canvas.height = canvas.parentElement?.clientHeight || window.innerHeight;
+
+ let animationFrameId: number;
+ let time = 0;
+
+ const handleResize = () => {
+ if (canvas.parentElement) {
+ width = canvas.width = canvas.parentElement.clientWidth;
+ height = canvas.height = canvas.parentElement.clientHeight;
+ }
+ };
+
+ window.addEventListener("resize", handleResize);
+
+ const render = () => {
+ ctx.clearRect(0, 0, width, height);
+ time += 0.02; // Rotation speed
+
+ const strandGap = 40; // Vertical distance between "base pairs"
+ const amplitude = 50; // Width of the helix
+ const frequency = 0.015; // Tightness of the loops
+
+ // Position helix on the right side (85% of width) to keep content clear
+ const centerX = width * 0.85;
+
+ ctx.lineWidth = 2;
+
+ // Calculate number of points based on container height
+ const numPoints = Math.ceil(height / strandGap) + 5;
+
+ for (let i = 0; i < numPoints; i++) {
+ // Scroll the helix slowly downward
+ const y = i * strandGap - (time * 10) % strandGap;
+
+ // Calculate rotation phase
+ const phase = y * frequency + time;
+
+ // Strand 1 (Cyan)
+ const x1 = centerX + Math.sin(phase) * amplitude;
+ // Strand 2 (Emerald) - Offset by PI
+ const x2 = centerX + Math.sin(phase + Math.PI) * amplitude;
+
+ // Depth calculation for 3D effect (fade when "back")
+ const depth1 = Math.cos(phase);
+ const depth2 = Math.cos(phase + Math.PI);
+
+ // Map depth (-1 to 1) to opacity (0.2 to 0.8)
+ const alpha1 = (depth1 + 1) / 2 * 0.6 + 0.2;
+ const alpha2 = (depth2 + 1) / 2 * 0.6 + 0.2;
+
+ // Draw Connector Line (Base Pair)
+ ctx.beginPath();
+ ctx.moveTo(x1, y);
+ ctx.lineTo(x2, y);
+ ctx.strokeStyle = `rgba(34, 211, 238, 0.05)`; // Very faint connector
+ ctx.stroke();
+
+ // Draw Strand 1 Particle
+ ctx.beginPath();
+ ctx.arc(x1, y, 4 + depth1, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(34, 211, 238, ${alpha1})`; // Cyan
+ ctx.fill();
+
+ // Draw Strand 2 Particle
+ ctx.beginPath();
+ ctx.arc(x2, y, 4 + depth2, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(52, 211, 153, ${alpha2})`; // Emerald
+ ctx.fill();
+ }
+
+ animationFrameId = requestAnimationFrame(render);
+ };
+
+ render();
+
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ cancelAnimationFrame(animationFrameId);
+ };
+ }, []);
+
+ return (
+
+ );
+};
+
+export default DNAHelix;
\ No newline at end of file
diff --git a/app/components/canvas/GravityWave.tsx b/app/components/canvas/GravityWave.tsx
new file mode 100644
index 0000000..7e2c9e7
--- /dev/null
+++ b/app/components/canvas/GravityWave.tsx
@@ -0,0 +1,123 @@
+"use client";
+
+import React, { useEffect, useRef } from "react";
+
+interface Props {
+ className?: string;
+}
+
+const GravityWave: React.FC = ({ className }) => {
+ const canvasRef = useRef(null);
+
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return;
+
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return;
+
+ // Initialize dimensions based on parent container
+ let width = canvas.width = canvas.parentElement?.clientWidth || window.innerWidth;
+ let height = canvas.height = canvas.parentElement?.clientHeight || window.innerHeight;
+
+ let animationFrameId: number;
+ let time = 0;
+
+ // Configuration
+ const gap = 50;
+ const rows = Math.ceil(height / gap) + 4;
+ const cols = Math.ceil(width / gap) + 4;
+
+ // Mouse state
+ const mouse = { x: -500, y: -500 };
+
+ const handleResize = () => {
+ // Resize based on parent element
+ if (canvas.parentElement) {
+ width = canvas.width = canvas.parentElement.clientWidth;
+ height = canvas.height = canvas.parentElement.clientHeight;
+ }
+ };
+
+ const handleMouseMove = (e: MouseEvent) => {
+ const rect = canvas.getBoundingClientRect();
+ mouse.x = e.clientX - rect.left;
+ mouse.y = e.clientY - rect.top;
+ };
+
+ window.addEventListener("resize", handleResize);
+ // Attach mouse move to the specific canvas/container, not window, if you want localized interaction
+ // But keeping it on window usually feels smoother for "approaching" the section
+ window.addEventListener("mousemove", handleMouseMove);
+
+ const render = () => {
+ ctx.clearRect(0, 0, width, height);
+ time += 0.02;
+
+ ctx.shadowBlur = 4;
+ ctx.shadowColor = "rgba(34, 211, 238, 0.5)";
+
+ const gradient = ctx.createLinearGradient(0, 0, width, height);
+ gradient.addColorStop(0, "rgba(34, 211, 238, 0.4)");
+ gradient.addColorStop(1, "rgba(52, 211, 153, 0.4)");
+
+ ctx.strokeStyle = gradient;
+ ctx.lineWidth = 1.5;
+
+ // Re-calculate rows/cols in case of resize
+ const currentRows = Math.ceil(height / gap) + 4;
+ const currentCols = Math.ceil(width / gap) + 4;
+
+ for (let iy = 0; iy < currentRows; iy++) {
+ const yBase = iy * gap;
+ ctx.beginPath();
+ for (let ix = 0; ix < currentCols; ix++) {
+ const xBase = ix * gap;
+
+ const waveOffset = Math.sin(ix * 0.2 + time) * 8 + Math.cos(iy * 0.3 + time) * 8;
+ const dx = xBase - mouse.x;
+ const dy = yBase - mouse.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+
+ const maxDist = 400;
+ let gravityX = 0;
+ let gravityY = 0;
+
+ if (dist < maxDist) {
+ const force = (maxDist - dist) / maxDist;
+ const power = force * 60;
+ const angle = Math.atan2(dy, dx);
+ gravityX = Math.cos(angle) * power;
+ gravityY = Math.sin(angle) * power;
+ }
+
+ const xFinal = xBase + gravityX;
+ const yFinal = yBase + waveOffset + gravityY;
+
+ if (ix === 0) ctx.moveTo(xFinal, yFinal);
+ else ctx.lineTo(xFinal, yFinal);
+ }
+ ctx.stroke();
+ }
+ animationFrameId = requestAnimationFrame(render);
+ };
+
+ render();
+
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ window.removeEventListener("mousemove", handleMouseMove);
+ cancelAnimationFrame(animationFrameId);
+ };
+ }, []);
+
+ return (
+
+ );
+};
+
+export default GravityWave;
\ No newline at end of file
diff --git a/app/components/canvas/NeuralNetwork.tsx b/app/components/canvas/NeuralNetwork.tsx
new file mode 100644
index 0000000..b12ee82
--- /dev/null
+++ b/app/components/canvas/NeuralNetwork.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import { useRef, useMemo } from "react";
+import { Canvas, useFrame } from "@react-three/fiber";
+import { Points, PointMaterial, Preload } from "@react-three/drei";
+import * as THREE from "three";
+
+function Particles(props: any) {
+ const ref = useRef(null!);
+
+ // Generate 5000 random points inside a sphere
+ const sphere = useMemo(() => {
+ const coords = new Float32Array(5000 * 3);
+ for (let i = 0; i < 5000; i++) {
+ const r = 1.2 * Math.cbrt(Math.random()); // Radius
+ const theta = Math.random() * 2 * Math.PI; // Theta
+ const phi = Math.acos(2 * Math.random() - 1); // Phi
+
+ const x = r * Math.sin(phi) * Math.cos(theta);
+ const y = r * Math.sin(phi) * Math.sin(theta);
+ const z = r * Math.cos(phi);
+
+ coords[i * 3] = x;
+ coords[i * 3 + 1] = y;
+ coords[i * 3 + 2] = z;
+ }
+ return coords;
+ }, []);
+
+ useFrame((state, delta) => {
+ if (ref.current) {
+ // Rotate the entire cloud slowly
+ ref.current.rotation.x -= delta / 10;
+ ref.current.rotation.y -= delta / 15;
+ }
+ });
+
+ return (
+
+
+
+
+
+ );
+}
+
+const NeuralNetwork = () => {
+ return (
+
+
+
+ );
+};
+
+export default NeuralNetwork;
\ No newline at end of file
diff --git a/app/components/canvas/NeuronNetwork.tsx b/app/components/canvas/NeuronNetwork.tsx
new file mode 100644
index 0000000..cc50741
--- /dev/null
+++ b/app/components/canvas/NeuronNetwork.tsx
@@ -0,0 +1,81 @@
+// src/components/canvas/NeuronNetwork.tsx
+"use client";
+
+import { useRef, useMemo } from "react";
+import { Canvas, useFrame } from "@react-three/fiber";
+import { Points, PointMaterial } from "@react-three/drei";
+import * as THREE from "three";
+
+function NeuronParticles({ count = 200 }) {
+ // Create a ref for the points to animate them
+ const points = useRef(null!);
+
+ // Generate random positions for the neurons
+ const positions = useMemo(() => {
+ const pos = new Float32Array(count * 3);
+ for (let i = 0; i < count; i++) {
+ // Spread particles across a wide area (x, y, z)
+ pos[i * 3] = (Math.random() - 0.5) * 25; // x
+ pos[i * 3 + 1] = (Math.random() - 0.5) * 25; // y
+ pos[i * 3 + 2] = (Math.random() - 0.5) * 10; // z
+ }
+ return pos;
+ }, [count]);
+
+ useFrame((state, delta) => {
+ if (points.current) {
+ // subtle rotation of the entire system
+ points.current.rotation.x -= delta / 50;
+ points.current.rotation.y -= delta / 60;
+
+ // Optional: Gentle wave motion could be added here
+ }
+ });
+
+ return (
+
+
+
+
+ {/* For true "connections" (lines), calculating distance between 200 points
+ every frame is heavy. A visual trick is to render a second layer
+ of slightly larger, fainter particles or use a custom shader.
+
+ However, for a clean "Neuron" look, we often just need the floating nodes
+ and a faint fog, or we can use the component from drei
+ if the count is low (<50).
+ */}
+
+ );
+}
+
+// A wrapper to handle the Canvas settings
+export default function NeuronNetwork() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/canvas/NeuronsGravity.tsx b/app/components/canvas/NeuronsGravity.tsx
new file mode 100644
index 0000000..7f2efcc
--- /dev/null
+++ b/app/components/canvas/NeuronsGravity.tsx
@@ -0,0 +1,183 @@
+"use client";
+
+import { useMemo, useRef } from "react";
+import { Canvas, useFrame, useThree } from "@react-three/fiber";
+import * as THREE from "three";
+import { Preload } from "@react-three/drei";
+
+// CONFIGURATION
+const PARTICLE_COUNT = 80;
+const CONNECT_DISTANCE = 3.5;
+const MOUSE_INFLUENCE_RADIUS = 6; // Radius of the mouse wave
+const WAVE_AMPLITUDE = 1.5; // How high the wave ripples (Z-axis)
+
+function NeuralMesh() {
+ const groupRef = useRef(null);
+ const particlesRef = useRef(null);
+ const linesRef = useRef(null);
+
+ // Get viewport to map mouse coordinates correctly to world space
+ const { viewport } = useThree();
+
+ // 1. Generate Initial Random Positions & Velocities
+ // We store "original positions" to calculate the wave offset from
+ const [positions, velocities, originalPositions] = useMemo(() => {
+ const pos = new Float32Array(PARTICLE_COUNT * 3);
+ const origPos = new Float32Array(PARTICLE_COUNT * 3);
+ const vel = [];
+
+ for (let i = 0; i < PARTICLE_COUNT; i++) {
+ const x = (Math.random() - 0.5) * 18;
+ const y = (Math.random() - 0.5) * 18;
+ const z = (Math.random() - 0.5) * 10;
+
+ pos[i * 3] = x;
+ pos[i * 3 + 1] = y;
+ pos[i * 3 + 2] = z;
+
+ origPos[i * 3] = x;
+ origPos[i * 3 + 1] = y;
+ origPos[i * 3 + 2] = z;
+
+ vel.push({
+ x: (Math.random() - 0.5) * 0.05, // Slower natural drift
+ y: (Math.random() - 0.5) * 0.05,
+ z: (Math.random() - 0.5) * 0.05,
+ });
+ }
+ return [pos, vel, origPos];
+ }, []);
+
+ useFrame((state, delta) => {
+ // 2. Map Mouse to World Coordinates
+ // state.pointer is normalized (-1 to 1). Convert to world units using viewport.
+ const mouseX = (state.pointer.x * viewport.width) / 2;
+ const mouseY = (state.pointer.y * viewport.height) / 2;
+
+ if (particlesRef.current && linesRef.current) {
+ const positionsAttr = particlesRef.current.geometry.attributes.position;
+ const currentPositions = positionsAttr.array as Float32Array;
+
+ // 3. Update Particles
+ for (let i = 0; i < PARTICLE_COUNT; i++) {
+ const i3 = i * 3;
+
+ // A. Natural Drift (Gravity)
+ // We use the "original" position as an anchor to prevent them from flying away too far
+ // but we add the velocity to keep them moving organically.
+ originalPositions[i3] += velocities[i].x * delta * 2;
+ originalPositions[i3 + 1] += velocities[i].y * delta * 2;
+
+ // Bounce logic for the anchor points
+ if (Math.abs(originalPositions[i3]) > 10) velocities[i].x *= -1;
+ if (Math.abs(originalPositions[i3 + 1]) > 10) velocities[i].y *= -1;
+
+ // B. Mouse Interaction (The Wave)
+ // Calculate distance from particle to mouse
+ const dx = mouseX - originalPositions[i3];
+ const dy = mouseY - originalPositions[i3 + 1];
+ const dist = Math.sqrt(dx * dx + dy * dy);
+
+ // Apply Wave Effect
+ // If the mouse is close, we disturb the position
+ let xOffset = 0;
+ let yOffset = 0;
+ let zOffset = 0;
+
+ if (dist < MOUSE_INFLUENCE_RADIUS) {
+ // 1. Repulsion force (XY Plane) - pushes them slightly aside
+ const force = (MOUSE_INFLUENCE_RADIUS - dist) / MOUSE_INFLUENCE_RADIUS;
+ const angle = Math.atan2(dy, dx);
+
+ xOffset = -Math.cos(angle) * force * 2; // Push away X
+ yOffset = -Math.sin(angle) * force * 2; // Push away Y
+
+ // 2. Wave Ripple (Z Plane) - Sine wave based on distance and time
+ // This creates the "water ripple" effect in 3D depth
+ zOffset = Math.sin(dist * 1.5 - state.clock.elapsedTime * 3) * WAVE_AMPLITUDE * force;
+ }
+
+ // Apply calculated positions
+ currentPositions[i3] = originalPositions[i3] + xOffset;
+ currentPositions[i3 + 1] = originalPositions[i3 + 1] + yOffset;
+ currentPositions[i3 + 2] = originalPositions[i3 + 2] + zOffset;
+ }
+ positionsAttr.needsUpdate = true;
+
+ // 4. Update Connections (Plexus)
+ // Re-calculate lines based on the NEW modified positions
+ const linePositions: number[] = [];
+
+ for (let i = 0; i < PARTICLE_COUNT; i++) {
+ for (let j = i + 1; j < PARTICLE_COUNT; j++) {
+ const x1 = currentPositions[i * 3];
+ const y1 = currentPositions[i * 3 + 1];
+ const z1 = currentPositions[i * 3 + 2];
+
+ const x2 = currentPositions[j * 3];
+ const y2 = currentPositions[j * 3 + 1];
+ const z2 = currentPositions[j * 3 + 2];
+
+ const dist = Math.sqrt(
+ Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)
+ );
+
+ if (dist < CONNECT_DISTANCE) {
+ linePositions.push(x1, y1, z1, x2, y2, z2);
+ }
+ }
+ }
+
+ linesRef.current.geometry.setAttribute(
+ "position",
+ new THREE.Float32BufferAttribute(linePositions, 3)
+ );
+ }
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default function NeuronsGravity() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/layout/Footer.tsx b/app/components/layout/Footer.tsx
index 8c35a2c..b4af7a3 100644
--- a/app/components/layout/Footer.tsx
+++ b/app/components/layout/Footer.tsx
@@ -5,7 +5,7 @@ import { motion } from "framer-motion";
export default function Footer() {
return (
-
) : (
-
+
)}
@@ -149,87 +149,72 @@ export default function Navbar() {
- {/* Mobile Menu – Slide from right + better visuals */}
+ {/* Mobile Menu Overlay */}
{isMobileMenuOpen && (
<>
- {/* Backdrop with subtle vignette */}
+ {/* Backdrop */}
setIsMobileMenuOpen(false)}
/>
- {/* Side sheet style menu */}
+ {/* Mobile Menu Content */}
-
- {/* Header */}
-
-
-
- Skyheal
-
-
+
+ {/* Menu Header */}
+
+
+ Navigation
+
{/* Menu Items */}
-
- {navItems.map((item) => (
+
diff --git a/app/components/sections/AIDiagnosis.tsx b/app/components/sections/AIDiagnosis.tsx
index ef9379d..94c60b7 100644
--- a/app/components/sections/AIDiagnosis.tsx
+++ b/app/components/sections/AIDiagnosis.tsx
@@ -17,6 +17,7 @@ import { useRef, useEffect, useState } from "react";
export default function AIDiagnosis() {
const containerRef = useRef(null);
+ const canvasContainerRef = useRef(null); // Ref for the wrapper of the canvas
const canvasRef = useRef(null);
const [modelLoaded, setModelLoaded] = useState(false);
const [scanProgress, setScanProgress] = useState(0);
@@ -28,7 +29,7 @@ export default function AIDiagnosis() {
const y = useTransform(scrollYProgress, [0, 0.5], [100, 0]);
const opacity = useTransform(scrollYProgress, [0, 0.3], [0, 1]);
- const scale = useTransform(scrollYProgress, [0, 0.5], [0.9, 1]);
+ const scale = useTransform(scrollYProgress, [0, 0.5], [0.95, 1]); // Subtle scale
// Simulate scan progress
useEffect(() => {
@@ -40,7 +41,7 @@ export default function AIDiagnosis() {
// Three.js setup
useEffect(() => {
- if (typeof window === "undefined" || !canvasRef.current) return;
+ if (typeof window === "undefined" || !canvasRef.current || !canvasContainerRef.current) return;
let animationId: number | undefined;
let scene: any;
@@ -53,8 +54,12 @@ export default function AIDiagnosis() {
const THREE = await import("three");
const { GLTFLoader, OrbitControls } = await import("three-stdlib");
+ // Get initial dimensions from the parent container
+ const width = canvasContainerRef.current?.clientWidth || 500;
+ const height = canvasContainerRef.current?.clientHeight || 500;
+
scene = new THREE.Scene();
- camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
+ camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
camera.position.set(0, 0, 5);
renderer = new THREE.WebGLRenderer({
@@ -62,17 +67,15 @@ export default function AIDiagnosis() {
alpha: true,
antialias: true,
});
- renderer.setSize(500, 500);
+ renderer.setSize(width, height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setClearColor(0x000000, 0);
// Lighting
scene.add(new THREE.AmbientLight(0xffffff, 0.8));
-
const dirLight1 = new THREE.DirectionalLight(0x6366f1, 1.2);
dirLight1.position.set(5, 5, 5);
scene.add(dirLight1);
-
const dirLight2 = new THREE.DirectionalLight(0xa855f7, 0.8);
dirLight2.position.set(-5, 3, -5);
scene.add(dirLight2);
@@ -85,6 +88,21 @@ export default function AIDiagnosis() {
controls.autoRotate = true;
controls.autoRotateSpeed = 1.5;
+ // Handle Resize - Critical for responsiveness
+ const handleResize = () => {
+ if (!canvasContainerRef.current || !camera || !renderer) return;
+ const newWidth = canvasContainerRef.current.clientWidth;
+ const newHeight = canvasContainerRef.current.clientHeight;
+
+ camera.aspect = newWidth / newHeight;
+ camera.updateProjectionMatrix();
+ renderer.setSize(newWidth, newHeight);
+ };
+
+ // Use ResizeObserver for robust sizing (handles container changes, not just window)
+ const resizeObserver = new ResizeObserver(() => handleResize());
+ resizeObserver.observe(canvasContainerRef.current!);
+
// Model loading
const loader = new GLTFLoader();
const modelURL = "/human_body.glb";
@@ -103,7 +121,6 @@ export default function AIDiagnosis() {
model.scale.setScalar(scaleFactor);
model.position.sub(center.multiplyScalar(scaleFactor));
- // Performance: disable shadows
model.traverse((child: any) => {
if (child.isMesh) {
child.castShadow = false;
@@ -114,8 +131,7 @@ export default function AIDiagnosis() {
scene.add(model);
setModelLoaded(true);
} catch (error) {
- console.error("Failed to load GLB model → using fallback", error);
-
+ console.warn("Using fallback geometry");
const geometry = new THREE.IcosahedronGeometry(1.5, 2);
const material = new THREE.MeshStandardMaterial({
color: 0x6366f1,
@@ -123,6 +139,7 @@ export default function AIDiagnosis() {
metalness: 0.7,
emissive: 0x3b82f6,
emissiveIntensity: 0.2,
+ wireframe: true, // Added wireframe for a more "tech" fallback look
});
model = new THREE.Mesh(geometry, material);
scene.add(model);
@@ -138,29 +155,22 @@ export default function AIDiagnosis() {
};
animate();
+
+ // Clean up specifically for this closure
+ return () => {
+ resizeObserver.disconnect();
+ };
};
- initThreeJS();
+ const cleanupPromise = initThreeJS();
- // Cleanup
return () => {
- if (animationId !== undefined) {
- cancelAnimationFrame(animationId);
- }
+ cleanupPromise.then((cleanup) => cleanup && cleanup());
+ if (animationId !== undefined) cancelAnimationFrame(animationId);
if (controls) controls.dispose();
if (renderer) renderer.dispose();
- if (scene) {
- scene.traverse((obj: any) => {
- if (obj.geometry) obj.geometry.dispose();
- if (obj.material) {
- if (Array.isArray(obj.material)) {
- obj.material.forEach((m: any) => m.dispose());
- } else {
- obj.material.dispose();
- }
- }
- });
- }
+ // Simplified scene disposal
+ if (scene) scene.clear();
};
}, []);
@@ -168,11 +178,11 @@ export default function AIDiagnosis() {
- {/* Ambient glows */}
-
-
+ {/* Ambient glows - Optimized for mobile by reducing blur radius slightly */}
+ {/*
+ */}
{/* Subtle grid */}
-
-
- {/* 3D Viewer Column */}
+
+
+
+ {/* --- 3D Viewer Column --- */}
+ {/* Order-2 on mobile ensures text comes first if desired, but default is fine */}
-
+ {/* Background Blur blob */}
+
-
- Devices comply with IEC 60601, IEC 62304 and relevant regional regulations. All data transmission uses end-to-end encryption, device authentication, secure pairing and full audit logging.
+
+ Built for the modern hospital. Our devices comply with IEC 60601 and HIPAA standards.
+ End-to-end encryption ensures patient data remains secure from the sensor to the cloud.
+
diff --git a/app/globals.css b/app/globals.css
index 7617077..ad68799 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -52,7 +52,6 @@ h6 {
}
.text-gradient {
- /* Updated to a silver/white shimmer instead of colors */
background: linear-gradient(135deg, #ffffff 0%, #a1a1aa 100%);
background-clip: text;
-webkit-background-clip: text;
@@ -101,4 +100,14 @@ h6 {
50% {
opacity: 0.5;
}
+}
+@layer utilities {
+ .scrollbar-none {
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+ }
+
+ .scrollbar-none::-webkit-scrollbar {
+ display: none;
+ }
}
\ No newline at end of file
diff --git a/app/page.tsx b/app/page.tsx
index f8f4e08..4025515 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,110 +1,177 @@
"use client";
-import { motion } from "framer-motion";
-import DNAHeroBackground from "./components/canvas/DNAHeroBackground";
+import { motion, type Variants } from "framer-motion";
+import { ArrowRight, Activity, ShieldCheck, Zap } from "lucide-react";
+import GravityWave from "./components/canvas/GravityWave";
import Navbar from "./components/layout/Navbar";
import AIVoiceSoap from "./components/sections/AIVoiceSoap";
import AIDiagnosis from "./components/sections/AIDiagnosis";
-// import AIPrescription from "./components/sections/AIPrescription";
import DeviceShowcase from "./components/sections/DeviceShowcase";
-// import TelehealthSolutions from "./components/sections/TelehealthSolutions";
import AppEcosystem from "./components/sections/AppEcosystem";
import Footer from "./components/layout/Footer";
-import { ArrowRight, Sparkles } from "lucide-react";
+
+const fadeInUp: Variants = {
+ hidden: { opacity: 0, y: 30 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.8,
+ ease: "easeOut" as const
+ }
+ }
+};
+
+const staggerContainer: Variants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.2,
+ delayChildren: 0.1
+ }
+ }
+};
export default function Home() {
return (
-
- {/* DNA Background – placed first with negative z-index so it's behind everything */}
-
-
+
+
+
+
+
+
- {/* Navbar – should be above background */}
-
-
-
+
-
- {/* Hero Section */}
-
-
-
- Institutional
- Healthcare{" "}
- AI
-
-
-
- A zero-compromise clinical infrastructure.
-
- Precision diagnostic models, automated clinical notes, and hyper-secure data layers.
-