Spaces:
Running
Running
| import { useState, useEffect } from "react"; | |
| import { Link as RouterLink } from "react-router-dom"; | |
| import { | |
| Box, | |
| Container, | |
| Typography, | |
| Button, | |
| Grid, | |
| Stack, | |
| Link, | |
| } from "@mui/material"; | |
| import { useSpring, animated } from "@react-spring/web"; | |
| import OpenInNewIcon from "@mui/icons-material/OpenInNew"; | |
| import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; | |
| import Layout from "../components/Layout"; | |
| import Section from "../components/Section"; | |
| import { useApps } from "../context/AppsContext"; | |
| // Floating Sticker Component with scroll parallax | |
| function FloatingSticker({ | |
| src, | |
| size, | |
| top, | |
| left, | |
| right, | |
| bottom, | |
| rotation = 0, | |
| floatRange = 15, | |
| floatSpeed = 6000, | |
| scrollFactor = 0.05, | |
| }) { | |
| const [floatOffset, setFloatOffset] = useState(0); | |
| const [scrollY, setScrollY] = useState(0); | |
| useEffect(() => { | |
| let startTime = Date.now(); | |
| let animationFrame; | |
| const animate = () => { | |
| const elapsed = Date.now() - startTime; | |
| const offset = | |
| Math.sin((elapsed / floatSpeed) * Math.PI * 2) * floatRange; | |
| setFloatOffset(offset); | |
| animationFrame = requestAnimationFrame(animate); | |
| }; | |
| animationFrame = requestAnimationFrame(animate); | |
| return () => cancelAnimationFrame(animationFrame); | |
| }, [floatSpeed, floatRange]); | |
| useEffect(() => { | |
| const handleScroll = () => setScrollY(window.scrollY); | |
| window.addEventListener("scroll", handleScroll, { passive: true }); | |
| return () => window.removeEventListener("scroll", handleScroll); | |
| }, []); | |
| const springProps = useSpring({ | |
| transform: `translateY(${floatOffset + scrollY * scrollFactor}px) rotate(${rotation}deg)`, | |
| config: { mass: 3, tension: 80, friction: 40 }, | |
| }); | |
| return ( | |
| <animated.img | |
| src={src} | |
| alt="" | |
| style={{ | |
| position: "absolute", | |
| top, | |
| left, | |
| right, | |
| bottom, | |
| width: size, | |
| height: "auto", | |
| pointerEvents: "none", | |
| zIndex: 2, | |
| ...springProps, | |
| }} | |
| /> | |
| ); | |
| } | |
| // Hero Section | |
| function Hero() { | |
| const [scrollY, setScrollY] = useState(0); | |
| useEffect(() => { | |
| const handleScroll = () => setScrollY(window.scrollY); | |
| window.addEventListener("scroll", handleScroll, { passive: true }); | |
| return () => window.removeEventListener("scroll", handleScroll); | |
| }, []); | |
| const videoParallax = useSpring({ | |
| transform: `translate(-45%, calc(-50% + ${scrollY * 0.15}px))`, | |
| config: { mass: 1, tension: 280, friction: 60 }, | |
| }); | |
| return ( | |
| <Box | |
| sx={{ | |
| position: "relative", | |
| minHeight: { xs: "85vh", md: "80vh" }, | |
| display: "flex", | |
| alignItems: { xs: "flex-end", md: "center" }, | |
| pb: { xs: 12, md: 0 }, | |
| backgroundColor: "#000", | |
| overflow: "hidden", | |
| // Curved bottom edge | |
| "&::after": { | |
| content: '""', | |
| position: "absolute", | |
| bottom: -1, | |
| left: 0, | |
| right: 0, | |
| height: { xs: 60, md: 90 }, | |
| background: "inherit", | |
| backgroundColor: "background.default", | |
| borderRadius: "100% 100% 0 0 / 100% 100% 0 0", | |
| transform: "translateY(50%)", | |
| }, | |
| }} | |
| > | |
| <animated.video | |
| autoPlay | |
| muted | |
| loop | |
| playsInline | |
| style={{ | |
| position: "absolute", | |
| top: "50%", | |
| left: "50%", | |
| minWidth: "100%", | |
| minHeight: "100%", | |
| width: "auto", | |
| height: "auto", | |
| opacity: 0.9, | |
| ...videoParallax, | |
| }} | |
| > | |
| <source | |
| src="/assets/Reachy-mini-wake-up-companion.mp4" | |
| type="video/mp4" | |
| /> | |
| </animated.video> | |
| {/* Overlay gradients + vignette */} | |
| <Box | |
| sx={{ | |
| position: "absolute", | |
| inset: 0, | |
| background: ` | |
| linear-gradient(to right, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0.4) 40%, rgba(0,0,0,0.15) 100%), | |
| linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 40%), | |
| radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.4) 100%) | |
| `, | |
| }} | |
| /> | |
| <Container maxWidth="lg" sx={{ position: "relative", zIndex: 10 }}> | |
| <Box sx={{ maxWidth: 640 }}> | |
| <Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 2 }}> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.6)", | |
| fontSize: 13, | |
| fontWeight: 500, | |
| }} | |
| > | |
| Open Source Robot | |
| </Typography> | |
| <Box | |
| sx={{ | |
| width: 4, | |
| height: 4, | |
| borderRadius: "50%", | |
| bgcolor: "rgba(255,255,255,0.3)", | |
| }} | |
| /> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.6)", | |
| fontSize: 13, | |
| fontWeight: 500, | |
| display: "flex", | |
| alignItems: "center", | |
| gap: 0.5, | |
| }} | |
| > | |
| Powered by{" "} | |
| <Box | |
| component="img" | |
| src="/assets/hf-logo.svg" | |
| alt="Hugging Face" | |
| sx={{ height: 14 }} | |
| /> | |
| </Typography> | |
| </Stack> | |
| <Box sx={{ position: "relative", display: "inline-block", mb: 2 }}> | |
| <Typography | |
| variant="h1" | |
| component="h1" | |
| sx={{ | |
| color: "white", | |
| background: | |
| "linear-gradient(135deg, #ffffff 0%, rgba(255,255,255,0.85) 100%)", | |
| backgroundClip: "text", | |
| WebkitBackgroundClip: "text", | |
| WebkitTextFillColor: "transparent", | |
| }} | |
| > | |
| Reachy Mini | |
| </Typography> | |
| </Box> | |
| <Typography | |
| variant="h5" | |
| component="p" | |
| sx={{ | |
| color: "rgba(255,255,255,0.75)", | |
| fontWeight: 400, | |
| mb: 4, | |
| lineHeight: 1.6, | |
| maxWidth: 520, | |
| }} | |
| > | |
| An expressive companion robot designed for{" "} | |
| <Box component="span" sx={{ color: "white", fontWeight: 500 }}> | |
| human interaction | |
| </Box> | |
| ,{" "} | |
| <Box component="span" sx={{ color: "white", fontWeight: 500 }}> | |
| creative coding | |
| </Box> | |
| , and{" "} | |
| <Box component="span" sx={{ color: "white", fontWeight: 500 }}> | |
| AI experimentation | |
| </Box> | |
| . | |
| </Typography> | |
| <Stack direction={{ xs: "column", sm: "row" }} spacing={2}> | |
| <Button | |
| component={RouterLink} | |
| to="/buy" | |
| variant="contained" | |
| size="large" | |
| sx={{ | |
| px: 4, | |
| py: 1.75, | |
| fontSize: 16, | |
| fontWeight: 600, | |
| background: "linear-gradient(135deg, #FF9500 0%, #ff7b00 100%)", | |
| boxShadow: "0 4px 24px rgba(255, 149, 0, 0.35)", | |
| "&:hover": { | |
| boxShadow: "0 8px 32px rgba(255, 149, 0, 0.5)", | |
| transform: "translateY(-2px)", | |
| }, | |
| }} | |
| > | |
| Buy Reachy Mini | |
| </Button> | |
| <Button | |
| variant="outlined" | |
| size="large" | |
| component={RouterLink} | |
| to="/getting-started" | |
| sx={{ | |
| px: 4, | |
| py: 1.75, | |
| fontSize: 16, | |
| fontWeight: 600, | |
| color: "rgba(255,255,255,0.9)", | |
| borderColor: "rgba(255,255,255,0.3)", | |
| "&:hover": { | |
| color: "white", | |
| borderColor: "rgba(255,255,255,0.6)", | |
| backgroundColor: "rgba(255,255,255,0.05)", | |
| }, | |
| }} | |
| > | |
| Get Started | |
| </Button> | |
| </Stack> | |
| </Box> | |
| </Container> | |
| </Box> | |
| ); | |
| } | |
| // Stats/Bento Section - Sober backgrounds, illustrations for color | |
| function StatsSection() { | |
| return ( | |
| <Section | |
| id="stats" | |
| sx={{ py: { xs: 8, md: 12 }, position: "relative", overflow: "visible" }} | |
| > | |
| <Grid container spacing={2} sx={{ overflow: "visible" }}> | |
| {/* Big stat - Open Source */} | |
| <Grid size={{ xs: 12, md: 8 }} sx={{ overflow: "visible" }}> | |
| <Box | |
| component={RouterLink} | |
| to="/getting-started" | |
| sx={{ | |
| height: { xs: 280, md: 320 }, | |
| borderRadius: 4, | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| p: { xs: 4, md: 6 }, | |
| position: "relative", | |
| display: "flex", | |
| flexDirection: "column", | |
| justifyContent: "space-between", | |
| // Clip only bottom and left, allow top and right overflow | |
| clipPath: "inset(-100px -50px 0 0 round 16px)", | |
| textDecoration: "none", | |
| color: "inherit", | |
| cursor: "pointer", | |
| transition: "border-color 0.3s ease, transform 0.3s ease", | |
| "&:hover": { | |
| borderColor: "rgba(255,255,255,0.2)", | |
| transform: "translateY(-2px)", | |
| }, | |
| }} | |
| > | |
| {/* How to create app illustration - floating */} | |
| <Box sx={{ display: { xs: "none", sm: "block" } }}> | |
| <FloatingSticker | |
| src="/assets/reachy-how-to-create-app.svg" | |
| size={336} | |
| top={-60} | |
| right={10} | |
| rotation={0} | |
| floatRange={8} | |
| floatSpeed={5000} | |
| scrollFactor={0.03} | |
| /> | |
| </Box> | |
| <Box sx={{ position: "relative", zIndex: 1 }}> | |
| <Typography | |
| sx={{ | |
| fontSize: { xs: 50, md: 60 }, | |
| fontWeight: 800, | |
| lineHeight: 1, | |
| color: "white", | |
| }} | |
| > | |
| Build your | |
| <br /> | |
| own robot | |
| </Typography> | |
| <Typography | |
| variant="h4" | |
| sx={{ color: "white", fontWeight: 600, mt: 1 }} | |
| > | |
| Get Started | |
| </Typography> | |
| </Box> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.5)", | |
| fontSize: 15, | |
| position: "relative", | |
| zIndex: 1, | |
| maxWidth: 400, | |
| }} | |
| > | |
| Follow our guides to assemble your Reachy Mini → | |
| </Typography> | |
| </Box> | |
| </Grid> | |
| {/* 30+ Apps with Hand Tracking GIF */} | |
| <Grid size={{ xs: 12, sm: 6, md: 4 }}> | |
| <Box | |
| component={RouterLink} | |
| to="/apps" | |
| sx={{ | |
| height: { xs: 280, md: 320 }, | |
| borderRadius: 4, | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| overflow: "hidden", | |
| position: "relative", | |
| textDecoration: "none", | |
| display: "block", | |
| transition: "all 0.3s ease", | |
| "&:hover": { borderColor: "rgba(255,255,255,0.2)" }, | |
| }} | |
| > | |
| {/* GIF Background */} | |
| <Box | |
| component="img" | |
| src="/assets/reachy-mini-hand-tracking.gif" | |
| alt="Real-time interaction" | |
| sx={{ | |
| position: "absolute", | |
| top: 0, | |
| left: 0, | |
| width: "100%", | |
| height: "100%", | |
| objectFit: "cover", | |
| }} | |
| /> | |
| {/* Overlay gradient */} | |
| <Box | |
| sx={{ | |
| position: "absolute", | |
| inset: 0, | |
| background: | |
| "linear-gradient(to top, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.3) 50%, rgba(0,0,0,0.1) 100%)", | |
| }} | |
| /> | |
| {/* Content */} | |
| <Box | |
| sx={{ | |
| position: "relative", | |
| zIndex: 1, | |
| height: "100%", | |
| p: { xs: 4, md: 5 }, | |
| display: "flex", | |
| flexDirection: "column", | |
| justifyContent: "flex-end", | |
| }} | |
| > | |
| <Typography | |
| sx={{ | |
| fontSize: { xs: 56, md: 72 }, | |
| fontWeight: 800, | |
| lineHeight: 1, | |
| color: "white", | |
| }} | |
| > | |
| Apps | |
| </Typography> | |
| <Box sx={{ mt: 1 }}> | |
| <Typography | |
| sx={{ color: "rgba(255,255,255,0.6)", fontSize: 14, mt: 0.5 }} | |
| > | |
| Explore ready-to-use app → | |
| </Typography> | |
| </Box> | |
| </Box> | |
| </Box> | |
| </Grid> | |
| {/* Community */} | |
| <Grid size={{ xs: 12, sm: 6, md: 4 }}> | |
| <Box | |
| component="a" | |
| href="https://discord.gg/2bAhWfXme9" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| sx={{ | |
| height: { xs: 200, md: 200 }, | |
| borderRadius: 4, | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| p: { xs: 4, md: 5 }, | |
| display: "flex", | |
| flexDirection: "column", | |
| justifyContent: "space-between", | |
| textDecoration: "none", | |
| transition: "all 0.3s ease", | |
| "&:hover": { borderColor: "rgba(255,255,255,0.2)" }, | |
| }} | |
| > | |
| <Box | |
| component="img" | |
| src="/assets/discord-logo.svg" | |
| alt="Discord" | |
| sx={{ width: 36, height: 36, opacity: 0.8 }} | |
| /> | |
| <Box> | |
| <Typography variant="h5" sx={{ color: "white", fontWeight: 600 }}> | |
| Join our Discord Community | |
| </Typography> | |
| <Typography | |
| sx={{ color: "rgba(255,255,255,0.5)", fontSize: 14, mt: 0.5 }} | |
| > | |
| We are already 4500+ Makers → | |
| </Typography> | |
| </Box> | |
| </Box> | |
| </Grid> | |
| {/* Python SDK */} | |
| <Grid size={{ xs: 12, md: 8 }}> | |
| <Box | |
| component="a" | |
| href="https://huggingface.co/docs/reachy_mini/SDK/readme" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| sx={{ | |
| height: { xs: 200, md: 200 }, | |
| borderRadius: 4, | |
| background: "#0d1117", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| p: { xs: 4, md: 5 }, | |
| display: "flex", | |
| alignItems: "center", | |
| gap: 4, | |
| textDecoration: "none", | |
| transition: "all 0.3s ease", | |
| overflow: "hidden", | |
| "&:hover": { borderColor: "rgba(255,255,255,0.2)" }, | |
| }} | |
| > | |
| <Box | |
| sx={{ | |
| fontFamily: '"JetBrains Mono", monospace', | |
| fontSize: { xs: 12, md: 14 }, | |
| color: "#e6edf3", | |
| flex: 1, | |
| whiteSpace: "pre", | |
| overflow: "hidden", | |
| }} | |
| > | |
| <Box component="span" sx={{ color: "#ff7b72" }}> | |
| from | |
| </Box>{" "} | |
| <Box component="span" sx={{ color: "#79c0ff" }}> | |
| reachy_mini | |
| </Box>{" "} | |
| <Box component="span" sx={{ color: "#ff7b72" }}> | |
| import | |
| </Box>{" "} | |
| <Box component="span" sx={{ color: "#ffa657" }}> | |
| ReachyMini | |
| </Box> | |
| {"\n\n"} | |
| <Box component="span" sx={{ color: "#ff7b72" }}> | |
| with | |
| </Box>{" "} | |
| <Box component="span" sx={{ color: "#ffa657" }}> | |
| ReachyMini | |
| </Box> | |
| <Box component="span" sx={{ color: "#8b949e" }}> | |
| () | |
| </Box>{" "} | |
| <Box component="span" sx={{ color: "#ff7b72" }}> | |
| as | |
| </Box>{" "} | |
| <Box component="span" sx={{ color: "#79c0ff" }}> | |
| mini | |
| </Box> | |
| :{"\n"} | |
| {" "}mini. | |
| <Box component="span" sx={{ color: "#d2a8ff" }}> | |
| goto_target | |
| </Box> | |
| (head=pose) | |
| </Box> | |
| <Box sx={{ textAlign: "right" }}> | |
| <Typography variant="h5" sx={{ color: "white", fontWeight: 600 }}> | |
| Discover the Python SDK | |
| </Typography> | |
| <Typography | |
| sx={{ color: "rgba(255,255,255,0.5)", fontSize: 14, mt: 0.5 }} | |
| > | |
| Full control in 3 lines → | |
| </Typography> | |
| </Box> | |
| </Box> | |
| </Grid> | |
| </Grid> | |
| </Section> | |
| ); | |
| } | |
| // Products Section - Minimal comparison | |
| function ProductsSection() { | |
| return ( | |
| <Section | |
| background="alt" | |
| sx={{ py: { xs: 8, md: 12 }, position: "relative", overflow: "visible" }} | |
| > | |
| {/* Stickers */} | |
| <Box sx={{ display: { xs: "none", lg: "block" } }}> | |
| <FloatingSticker | |
| src="/assets/reachies/captain.png" | |
| size={240} | |
| top={80} | |
| left={60} | |
| rotation={-8} | |
| floatRange={12} | |
| floatSpeed={5500} | |
| scrollFactor={0.03} | |
| /> | |
| </Box> | |
| <Box sx={{ textAlign: "center", mb: 8 }}> | |
| <Typography variant="h2" sx={{ mb: 2 }}> | |
| Two ways to Reachy | |
| </Typography> | |
| <Typography | |
| variant="body1" | |
| color="text.secondary" | |
| sx={{ maxWidth: 500, mx: "auto" }} | |
| > | |
| Choose wireless for standalone use, or Lite for a budget-friendly | |
| tethered experience. | |
| </Typography> | |
| </Box> | |
| <Grid container spacing={4} justifyContent="center"> | |
| {/* Wireless */} | |
| <Grid size={{ xs: 12, md: 5 }}> | |
| <Box | |
| sx={{ | |
| p: 5, | |
| borderRadius: 4, | |
| border: "2px solid", | |
| borderColor: "primary.main", | |
| background: | |
| "linear-gradient(135deg, rgba(255,149,0,0.03) 0%, transparent 100%)", | |
| textAlign: "center", | |
| position: "relative", | |
| }} | |
| > | |
| <Box | |
| sx={{ | |
| position: "absolute", | |
| top: -12, | |
| left: "50%", | |
| transform: "translateX(-50%)", | |
| px: 2, | |
| py: 0.5, | |
| borderRadius: 50, | |
| background: "linear-gradient(135deg, #FF9500 0%, #ff7b00 100%)", | |
| }} | |
| > | |
| <Typography | |
| sx={{ | |
| color: "white", | |
| fontSize: 12, | |
| fontWeight: 700, | |
| textTransform: "uppercase", | |
| }} | |
| > | |
| Most Popular | |
| </Typography> | |
| </Box> | |
| <Typography variant="h3" sx={{ mt: 2, mb: 1 }}> | |
| Reachy Mini | |
| </Typography> | |
| <Typography color="text.secondary" sx={{ mb: 3 }}> | |
| Wireless • On-board compute | |
| </Typography> | |
| <Typography | |
| sx={{ | |
| fontSize: 56, | |
| fontWeight: 800, | |
| mb: 3, | |
| background: "linear-gradient(135deg, #FF9500 0%, #ff7b00 100%)", | |
| WebkitBackgroundClip: "text", | |
| WebkitTextFillColor: "transparent", | |
| }} | |
| > | |
| $449 | |
| </Typography> | |
| <Stack | |
| spacing={1} | |
| sx={{ mb: 4, textAlign: "left", maxWidth: 280, mx: "auto" }} | |
| > | |
| {[ | |
| "Raspberry Pi 4 on-board", | |
| "Wi-Fi + USB", | |
| "Camera, 4 mics, speaker", | |
| "Accelerometer", | |
| ].map((item) => ( | |
| <Typography | |
| key={item} | |
| sx={{ fontSize: 14, color: "text.secondary" }} | |
| > | |
| ✓ {item} | |
| </Typography> | |
| ))} | |
| </Stack> | |
| <Button | |
| variant="contained" | |
| size="large" | |
| fullWidth | |
| href="https://buy.stripe.com/9B65kFfFlaKFbY34W873G03" | |
| target="_blank" | |
| sx={{ py: 1.5 }} | |
| > | |
| Order Now | |
| </Button> | |
| </Box> | |
| </Grid> | |
| {/* Lite */} | |
| <Grid size={{ xs: 12, md: 5 }}> | |
| <Box | |
| sx={{ | |
| p: 5, | |
| borderRadius: 4, | |
| border: "1px solid", | |
| borderColor: "divider", | |
| textAlign: "center", | |
| }} | |
| > | |
| <Typography variant="h3" sx={{ mt: 2, mb: 1 }}> | |
| Reachy Mini Lite | |
| </Typography> | |
| <Typography color="text.secondary" sx={{ mb: 3 }}> | |
| USB • External compute | |
| </Typography> | |
| <Typography | |
| sx={{ | |
| fontSize: 56, | |
| fontWeight: 800, | |
| mb: 3, | |
| color: "text.primary", | |
| }} | |
| > | |
| $299 | |
| </Typography> | |
| <Stack | |
| spacing={1} | |
| sx={{ mb: 4, textAlign: "left", maxWidth: 280, mx: "auto" }} | |
| > | |
| {[ | |
| "Your Mac/PC as brain", | |
| "USB only", | |
| "Camera, 4 mics, speaker", | |
| "Same motion capabilities", | |
| ].map((item) => ( | |
| <Typography | |
| key={item} | |
| sx={{ fontSize: 14, color: "text.secondary" }} | |
| > | |
| ✓ {item} | |
| </Typography> | |
| ))} | |
| </Stack> | |
| <Button | |
| variant="outlined" | |
| size="large" | |
| fullWidth | |
| href="https://buy.stripe.com/6oUfZj78P1a5e6b0FS73G02" | |
| target="_blank" | |
| sx={{ py: 1.5 }} | |
| > | |
| Order Now | |
| </Button> | |
| </Box> | |
| </Grid> | |
| </Grid> | |
| {/* Lead time notice */} | |
| <Box sx={{ textAlign: "center", mt: 5 }}> | |
| <Typography | |
| variant="body1" | |
| sx={{ | |
| color: "text.primary", | |
| fontWeight: 600, | |
| }} | |
| > | |
| Current Lead time: 90 days after purchase | |
| </Typography> | |
| <Typography | |
| variant="body2" | |
| sx={{ | |
| color: "text.secondary", | |
| mt: 1, | |
| maxWidth: 520, | |
| mx: "auto", | |
| lineHeight: 1.7, | |
| }} | |
| > | |
| <strong>Import duties:</strong> EU/UK + US/Canada ship duty-paid (DDP). | |
| <br /> | |
| Other destinations may incur local import duties/taxes on delivery (DAP). | |
| </Typography> | |
| </Box> | |
| <Typography | |
| variant="body2" | |
| color="text.secondary" | |
| sx={{ textAlign: "center", mt: 3 }} | |
| > | |
| Both ship as DIY kits. Assembly takes ~2 hours.{" "} | |
| <Link component={RouterLink} to="/getting-started"> | |
| Watch the guide → | |
| </Link> | |
| </Typography> | |
| </Section> | |
| ); | |
| } | |
| // Apps Showcase - Sober design with illustrations | |
| function AppsShowcase() { | |
| const { apps } = useApps(); | |
| // Round down to nearest 10 (e.g., 35 → 30, 42 → 40) | |
| const appsCountRounded = Math.floor(apps.length / 10) * 10; | |
| return ( | |
| <Box | |
| sx={{ | |
| py: { xs: 8, md: 12 }, | |
| background: "#0a0a12", | |
| position: "relative", | |
| overflow: "visible", | |
| }} | |
| > | |
| {/* Sticker */} | |
| <Box sx={{ display: { xs: "none", lg: "block" } }}> | |
| <FloatingSticker | |
| src="/assets/reachies/jazzman.png" | |
| size={240} | |
| top={40} | |
| right={80} | |
| rotation={10} | |
| floatRange={10} | |
| floatSpeed={5800} | |
| scrollFactor={0.04} | |
| /> | |
| </Box> | |
| <Container maxWidth="lg"> | |
| {/* Header */} | |
| <Box sx={{ textAlign: "center", mb: 8 }}> | |
| <Typography | |
| variant="overline" | |
| sx={{ | |
| color: "rgba(255,255,255,0.5)", | |
| mb: 2, | |
| display: "block", | |
| letterSpacing: "0.15em", | |
| }} | |
| > | |
| App Ecosystem | |
| </Typography> | |
| <Typography variant="h2" sx={{ color: "white", mb: 3 }}> | |
| {appsCountRounded}+ apps, one click install | |
| </Typography> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.5)", | |
| maxWidth: 500, | |
| mx: "auto", | |
| lineHeight: 1.7, | |
| }} | |
| > | |
| From AI conversations to hand tracking - explore what the community | |
| has built or create your own and share it with the world. | |
| </Typography> | |
| </Box> | |
| {/* Featured App - AI Companion (large) */} | |
| <Box | |
| sx={{ | |
| mb: 4, | |
| borderRadius: 4, | |
| overflow: "hidden", | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| display: "flex", | |
| flexDirection: { xs: "column", md: "row" }, | |
| }} | |
| > | |
| {/* Illustration */} | |
| <Box | |
| sx={{ | |
| flex: { xs: "none", md: 1 }, | |
| height: { xs: 250, md: "auto" }, | |
| minHeight: { md: 320 }, | |
| display: "flex", | |
| alignItems: "center", | |
| justifyContent: "center", | |
| overflow: "hidden", | |
| }} | |
| > | |
| <Box | |
| component="img" | |
| src="/assets/reachy-conversation-app.jpg" | |
| alt="AI Companion" | |
| sx={{ | |
| width: "100%", | |
| height: "100%", | |
| objectFit: "cover", | |
| }} | |
| /> | |
| </Box> | |
| {/* Content */} | |
| <Box | |
| sx={{ | |
| flex: { xs: "none", md: 1 }, | |
| p: { xs: 4, md: 6 }, | |
| display: "flex", | |
| flexDirection: "column", | |
| justifyContent: "center", | |
| }} | |
| > | |
| <Box | |
| sx={{ | |
| display: "inline-flex", | |
| alignItems: "center", | |
| gap: 1, | |
| px: 2, | |
| py: 0.5, | |
| mb: 2, | |
| borderRadius: 50, | |
| background: "rgba(255,255,255,0.08)", | |
| border: "1px solid rgba(255,255,255,0.1)", | |
| width: "fit-content", | |
| }} | |
| > | |
| <Box | |
| sx={{ | |
| width: 6, | |
| height: 6, | |
| borderRadius: "50%", | |
| bgcolor: "rgba(255,255,255,0.5)", | |
| }} | |
| /> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.7)", | |
| fontSize: 11, | |
| fontWeight: 600, | |
| textTransform: "uppercase", | |
| letterSpacing: "0.05em", | |
| }} | |
| > | |
| Featured | |
| </Typography> | |
| </Box> | |
| <Typography variant="h3" sx={{ color: "white", mb: 2 }}> | |
| AI Companion | |
| </Typography> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.6)", | |
| mb: 4, | |
| lineHeight: 1.8, | |
| maxWidth: 400, | |
| }} | |
| > | |
| Have a conversation with Reachy! Powered by LLMs, it understands | |
| what you say and responds with expressive movements and speech. | |
| </Typography> | |
| <Button | |
| component={RouterLink} | |
| to="/apps" | |
| variant="contained" | |
| endIcon={<ArrowForwardIcon />} | |
| > | |
| Try it now | |
| </Button> | |
| </Box> | |
| </Box> | |
| {/* Other apps grid */} | |
| <Grid container spacing={3}> | |
| {/* Hand Tracking */} | |
| <Grid size={{ xs: 12, md: 6 }}> | |
| <Box | |
| sx={{ | |
| borderRadius: 4, | |
| overflow: "hidden", | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| display: "flex", | |
| flexDirection: { xs: "column", sm: "row" }, | |
| height: { xs: "auto", md: 200 }, | |
| transition: "border-color 0.3s", | |
| "&:hover": { borderColor: "rgba(255,255,255,0.2)" }, | |
| }} | |
| > | |
| <Box | |
| sx={{ | |
| width: { xs: "100%", sm: 200 }, | |
| height: { xs: 150, sm: "auto" }, | |
| flexShrink: 0, | |
| overflow: "hidden", | |
| }} | |
| > | |
| <Box | |
| component="img" | |
| src="/assets/reachy-hand-tracking-app.jpg" | |
| alt="Hand Tracking" | |
| sx={{ | |
| width: "100%", | |
| height: "100%", | |
| objectFit: "cover", | |
| }} | |
| /> | |
| </Box> | |
| <Box | |
| sx={{ | |
| p: 3, | |
| display: "flex", | |
| flexDirection: "column", | |
| justifyContent: "center", | |
| }} | |
| > | |
| <Typography variant="h5" sx={{ color: "white", mb: 1 }}> | |
| Hand Tracking | |
| </Typography> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.5)", | |
| fontSize: 14, | |
| lineHeight: 1.6, | |
| }} | |
| > | |
| Reachy follows your hand movements in real-time using OpenCV. | |
| </Typography> | |
| </Box> | |
| </Box> | |
| </Grid> | |
| {/* More apps CTA */} | |
| <Grid size={{ xs: 12, md: 6 }}> | |
| <Box | |
| component={RouterLink} | |
| to="/apps" | |
| sx={{ | |
| borderRadius: 4, | |
| height: { xs: 150, md: 200 }, | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| display: "flex", | |
| flexDirection: "column", | |
| alignItems: "center", | |
| justifyContent: "center", | |
| textDecoration: "none", | |
| transition: "all 0.3s", | |
| "&:hover": { borderColor: "rgba(255,255,255,0.2)" }, | |
| }} | |
| > | |
| <Typography | |
| sx={{ | |
| fontSize: 48, | |
| fontWeight: 800, | |
| color: "white", | |
| mb: 1, | |
| }} | |
| > | |
| +{appsCountRounded} | |
| </Typography> | |
| <Typography | |
| sx={{ color: "rgba(255,255,255,0.7)", fontWeight: 600 }} | |
| > | |
| more apps to explore | |
| </Typography> | |
| <Typography | |
| sx={{ color: "rgba(255,255,255,0.4)", fontSize: 13, mt: 0.5 }} | |
| > | |
| Browse all → | |
| </Typography> | |
| </Box> | |
| </Grid> | |
| </Grid> | |
| {/* Build your own CTA */} | |
| <Box sx={{ textAlign: "center", mt: 6 }}> | |
| <Typography sx={{ color: "rgba(255,255,255,0.4)", fontSize: 14 }}> | |
| Got an idea?{" "} | |
| <Link | |
| href="https://huggingface.co/docs/reachy_mini/" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| sx={{ | |
| color: "primary.main", | |
| textDecoration: "none", | |
| "&:hover": { textDecoration: "underline" }, | |
| }} | |
| > | |
| Build your own app → | |
| </Link> | |
| </Typography> | |
| </Box> | |
| </Container> | |
| </Box> | |
| ); | |
| } | |
| // Community Section | |
| function CommunitySection() { | |
| return ( | |
| <Section | |
| sx={{ py: { xs: 8, md: 12 }, position: "relative", overflow: "visible" }} | |
| > | |
| <Box sx={{ display: { xs: "none", md: "block" } }}> | |
| <FloatingSticker | |
| src="/assets/reachies/cowboy.png" | |
| size={280} | |
| top={-20} | |
| left={100} | |
| rotation={-10} | |
| floatRange={12} | |
| floatSpeed={5500} | |
| scrollFactor={0.04} | |
| /> | |
| <FloatingSticker | |
| src="/assets/reachies/astronaut.png" | |
| size={300} | |
| bottom={-40} | |
| right={120} | |
| rotation={8} | |
| floatRange={15} | |
| floatSpeed={6500} | |
| scrollFactor={0.05} | |
| /> | |
| </Box> | |
| <Box | |
| sx={{ | |
| background: "#0f0f1a", | |
| border: "1px solid rgba(255,255,255,0.08)", | |
| borderRadius: 4, | |
| p: { xs: 5, md: 8 }, | |
| textAlign: "center", | |
| color: "white", | |
| position: "relative", | |
| }} | |
| > | |
| <Box sx={{ position: "relative", zIndex: 1 }}> | |
| <Typography variant="h2" sx={{ mb: 2 }}> | |
| Join 4500+ makers | |
| </Typography> | |
| <Typography | |
| sx={{ | |
| color: "rgba(255,255,255,0.6)", | |
| maxWidth: 500, | |
| mx: "auto", | |
| mb: 4, | |
| lineHeight: 1.8, | |
| }} | |
| > | |
| Connect with other Reachy Mini owners on Discord. Share your | |
| projects, get help, and stay updated on the latest developments. | |
| </Typography> | |
| <Button | |
| variant="contained" | |
| size="large" | |
| href="https://discord.gg/2bAhWfXme9" | |
| target="_blank" | |
| endIcon={<OpenInNewIcon />} | |
| > | |
| Join Discord | |
| </Button> | |
| </Box> | |
| </Box> | |
| </Section> | |
| ); | |
| } | |
| // Final CTA | |
| function FinalCTA() { | |
| return ( | |
| <Section background="alt" sx={{ py: { xs: 8, md: 12 } }}> | |
| <Box sx={{ textAlign: "center", maxWidth: 600, mx: "auto" }}> | |
| <Typography variant="h2" sx={{ mb: 3 }}> | |
| Ready to meet Reachy? | |
| </Typography> | |
| <Typography | |
| variant="body1" | |
| color="text.secondary" | |
| sx={{ mb: 5, lineHeight: 1.8 }} | |
| > | |
| Get your own expressive companion robot and join the community of | |
| makers building the future of human-robot interaction. | |
| </Typography> | |
| <Stack | |
| direction={{ xs: "column", sm: "row" }} | |
| spacing={2} | |
| justifyContent="center" | |
| > | |
| <Button | |
| variant="contained" | |
| size="large" | |
| component={RouterLink} | |
| to="/buy" | |
| sx={{ px: 5, py: 1.75, fontSize: 16 }} | |
| > | |
| Buy Reachy Mini | |
| </Button> | |
| </Stack> | |
| {/* <Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 1, sm: 4 }} justifyContent="center" sx={{ mt: 5, color: 'text.secondary' }}> | |
| <Typography variant="body2">✓ Free worldwide shipping</Typography> | |
| <Typography variant="body2">✓ 30-day returns</Typography> | |
| <Typography variant="body2">✓ 1-year warranty</Typography> | |
| </Stack> */} | |
| </Box> | |
| </Section> | |
| ); | |
| } | |
| // Main Home Page | |
| export default function Home() { | |
| return ( | |
| <Layout transparentHeader> | |
| <Hero /> | |
| <StatsSection /> | |
| <ProductsSection /> | |
| <AppsShowcase /> | |
| <CommunitySection /> | |
| <FinalCTA /> | |
| </Layout> | |
| ); | |
| } | |