3 Commits

Author SHA1 Message Date
a1af3da06d Add src/components/sections/canvas/CanvasScrollVideo.tsx 2026-03-10 20:01:06 +00:00
69e0eda1e5 Update src/app/page.tsx 2026-03-10 20:01:06 +00:00
afd79e7f80 Merge version_2 into main
Merge version_2 into main
2026-03-10 19:57:41 +00:00
2 changed files with 290 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ import SocialProofOne from '@/components/sections/socialProof/SocialProofOne';
import TestimonialCardFifteen from '@/components/sections/testimonial/TestimonialCardFifteen'; import TestimonialCardFifteen from '@/components/sections/testimonial/TestimonialCardFifteen';
import ContactSplit from '@/components/sections/contact/ContactSplit'; import ContactSplit from '@/components/sections/contact/ContactSplit';
import FooterLogoReveal from '@/components/sections/footer/FooterLogoReveal'; import FooterLogoReveal from '@/components/sections/footer/FooterLogoReveal';
import CanvasScrollVideo from '@/components/sections/canvas/CanvasScrollVideo';
import { Award, Badge, BookOpen, Brain, DollarSign, Eye, Heart, Layers, Lock, Mail, MessageSquare, Sparkles, Target, TrendingUp, Zap, BarChart3 } from 'lucide-react'; import { Award, Badge, BookOpen, Brain, DollarSign, Eye, Heart, Layers, Lock, Mail, MessageSquare, Sparkles, Target, TrendingUp, Zap, BarChart3 } from 'lucide-react';
export default function LandingPage() { export default function LandingPage() {
@@ -67,6 +68,10 @@ export default function LandingPage() {
/> />
</div> </div>
<div id="canvas-scroll" data-section="canvas-scroll">
<CanvasScrollVideo />
</div>
<div id="tutoring" data-section="tutoring"> <div id="tutoring" data-section="tutoring">
<SplitAbout <SplitAbout
title="Transparent Tutoring Built on Trust" title="Transparent Tutoring Built on Trust"

View File

@@ -0,0 +1,285 @@
"use client";
import { useEffect, useRef, useState } from "react";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
interface Particle {
x: number;
y: number;
vx: number;
vy: number;
size: number;
opacity: number;
hue: number;
}
const CanvasScrollVideo: React.FC = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const particlesRef = useRef<Particle[]>([]);
const scrollProgressRef = useRef(0);
const cameraZRef = useRef(8);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
// Set canvas size
const updateCanvasSize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
updateCanvasSize();
// Initialize particles (levitating books with neon glow)
const initializeParticles = () => {
const particles: Particle[] = [];
for (let i = 0; i < 40; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2,
size: Math.random() * 3 + 1,
opacity: Math.random() * 0.7 + 0.3,
hue: Math.random() * 60 + 240 // Purple to violet range
});
}
particlesRef.current = particles;
};
initializeParticles();
// Draw apartment window frame
const drawApartmentWindow = (progress: number) => {
// Warm sunset-gold background
const goldGrad = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
goldGrad.addColorStop(0, "#1a1a2e"); // Deep purple
goldGrad.addColorStop(0.5, "#d4a574"); // Warm sunset gold
goldGrad.addColorStop(1, "#2d1b4e"); // Deep purple
ctx.fillStyle = goldGrad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Window frame (apartment building window)
const frameWidth = canvas.width * 0.6;
const frameHeight = canvas.height * 0.7;
const frameX = (canvas.width - frameWidth) / 2;
const frameY = (canvas.height - frameHeight) / 2;
// Outer frame shadow
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
ctx.shadowBlur = 20;
ctx.strokeStyle = "#5a3d3d";
ctx.lineWidth = 8;
ctx.strokeRect(frameX, frameY, frameWidth, frameHeight);
ctx.shadowColor = "transparent";
// Window panes
ctx.strokeStyle = "#8b7355";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(frameX + frameWidth / 2, frameY);
ctx.lineTo(frameX + frameWidth / 2, frameY + frameHeight);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(frameX, frameY + frameHeight / 2);
ctx.lineTo(frameX + frameWidth, frameY + frameHeight / 2);
ctx.stroke();
// Inner glass reflection (gradient)
const glassGrad = ctx.createLinearGradient(frameX, frameY, frameX + frameWidth, frameY + frameHeight);
glassGrad.addColorStop(0, "rgba(255, 255, 255, 0.05)");
glassGrad.addColorStop(0.5, "rgba(255, 255, 255, 0)");
glassGrad.addColorStop(1, "rgba(212, 165, 116, 0.1)");
ctx.fillStyle = glassGrad;
ctx.fillRect(frameX, frameY, frameWidth, frameHeight);
};
// Draw study room elements
const drawStudyRoom = (progress: number) => {
const roomWidth = canvas.width * 0.5;
const roomHeight = canvas.height * 0.5;
const roomX = (canvas.width - roomWidth) / 2;
const roomY = (canvas.height - roomHeight) / 2;
// Room background with warm tones
const roomGrad = ctx.createLinearGradient(roomX, roomY, roomX + roomWidth, roomY + roomHeight);
roomGrad.addColorStop(0, "#3d2817");
roomGrad.addColorStop(0.5, "#6b4226");
roomGrad.addColorStop(1, "#2a1810");
ctx.fillStyle = roomGrad;
ctx.fillRect(roomX, roomY, roomWidth, roomHeight);
// Desk
ctx.fillStyle = "#8b6f47";
ctx.fillRect(roomX + roomWidth * 0.1, roomY + roomHeight * 0.6, roomWidth * 0.8, roomHeight * 0.3);
ctx.fillStyle = "#5a4a2a";
ctx.fillRect(roomX + roomWidth * 0.1, roomY + roomHeight * 0.5, roomWidth * 0.8, roomHeight * 0.1);
// Teenager at desk (simplified silhouette)
ctx.fillStyle = "#1a0a0a";
// Head
ctx.beginPath();
ctx.arc(roomX + roomWidth * 0.3, roomY + roomHeight * 0.35, roomHeight * 0.08, 0, Math.PI * 2);
ctx.fill();
// Torso
ctx.fillRect(roomX + roomWidth * 0.25, roomY + roomHeight * 0.42, roomWidth * 0.1, roomHeight * 0.15);
// Arms
ctx.fillRect(roomX + roomWidth * 0.15, roomY + roomHeight * 0.48, roomWidth * 0.15, roomHeight * 0.04);
};
// Draw levitating books with neon glow
const drawLevitatingBooks = (progress: number) => {
const bookPositions = [
{ x: 0.2, y: 0.25, rotation: Math.sin(progress * Math.PI * 2) * 0.3 },
{ x: 0.5, y: 0.15, rotation: Math.cos(progress * Math.PI * 2) * 0.3 },
{ x: 0.75, y: 0.3, rotation: Math.sin(progress * Math.PI * 2 + Math.PI / 3) * 0.3 },
{ x: 0.35, y: 0.05, rotation: Math.cos(progress * Math.PI * 2 + Math.PI / 2) * 0.3 }
];
bookPositions.forEach((pos, idx) => {
const bookX = canvas.width * pos.x;
const bookY = canvas.height * pos.y + Math.sin(progress * Math.PI * 2 + idx) * 15;
// Book neon glow
ctx.shadowColor = `hsl(${240 + idx * 30}, 100%, 50%)`;
ctx.shadowBlur = 25;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Book shape
ctx.save();
ctx.translate(bookX, bookY);
ctx.rotate(pos.rotation);
ctx.fillStyle = `hsl(${240 + idx * 30}, 100%, 35%)`;
ctx.fillRect(-20, -30, 40, 60);
ctx.strokeStyle = `hsl(${240 + idx * 30}, 100%, 60%)`;
ctx.lineWidth = 2;
ctx.strokeRect(-20, -30, 40, 60);
ctx.restore();
});
ctx.shadowColor = "transparent";
};
// Draw glowing math symbols
const drawMathSymbols = (progress: number) => {
const symbols = ["∫", "∑", "∞", "π", "√", "≈", "±"];
symbols.forEach((symbol, idx) => {
const x = canvas.width * (0.15 + (idx * 0.12));
const y = canvas.height * (0.45 + Math.sin(progress * Math.PI * 2 + idx) * 0.1);
const hue = 270 + idx * 15;
ctx.save();
ctx.shadowColor = `hsl(${hue}, 100%, 50%)`;
ctx.shadowBlur = 15;
ctx.font = "italic 28px serif";
ctx.fillStyle = `hsl(${hue}, 100%, 60%)`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.globalAlpha = 0.6 + Math.sin(progress * Math.PI * 2 + idx) * 0.3;
ctx.fillText(symbol, x, y);
ctx.restore();
});
};
// Draw particles (levitating magical elements)
const drawParticles = () => {
particlesRef.current.forEach((particle) => {
particle.x += particle.vx;
particle.y += particle.vy;
// Bounce off edges
if (particle.x < 0 || particle.x > canvas.width) particle.vx *= -1;
if (particle.y < 0 || particle.y > canvas.height) particle.vy *= -1;
// Neon glow effect
ctx.shadowColor = `hsl(${particle.hue}, 100%, 50%)`;
ctx.shadowBlur = 10;
ctx.fillStyle = `hsla(${particle.hue}, 100%, 50%, ${particle.opacity})`;
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
ctx.fill();
});
};
// Animation loop
const animate = () => {
const progress = scrollProgressRef.current;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw background and apartment window
drawApartmentWindow(progress);
// Camera push-in effect (zoom in as progress increases)
ctx.save();
const zoomLevel = 1 + progress * 0.5;
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.scale(zoomLevel, zoomLevel);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
// Draw study room elements
drawStudyRoom(progress);
drawLevitatingBooks(progress);
drawMathSymbols(progress);
drawParticles();
ctx.restore();
requestAnimationFrame(animate);
};
animate();
// Setup scroll trigger
if (containerRef.current) {
ScrollTrigger.create({
trigger: containerRef.current,
onUpdate: (self) => {
scrollProgressRef.current = self.progress;
}
});
}
// Handle window resize
const handleResize = () => {
updateCanvasSize();
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
};
}, []);
return (
<div
ref={containerRef}
className="relative w-full h-screen overflow-hidden bg-gradient-to-b from-purple-900 via-amber-800 to-purple-900"
style={{
background: "linear-gradient(180deg, #1a1a2e 0%, #d4a574 50%, #2d1b4e 100%)"
}}
>
<canvas
ref={canvasRef}
className="w-full h-full"
style={{
display: "block", background: "transparent"
}}
/>
{/* Optional: Add decorative elements around the canvas */}
<div className="absolute inset-0 pointer-events-none">
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent" />
</div>
</div>
);
};
export default CanvasScrollVideo;