Feat/landing revamp (#3)

* docs: add AGENTS.md for repository guidelines and project structure

- Introduced AGENTS.md to outline project structure, build commands, coding style, testing guidelines, and commit/pull request practices.
- Included detailed sections on module organization and naming conventions to enhance developer onboarding and consistency.

* feat: enhance landing page and configuration for improved user experience

- Updated next.config.ts to pin Turbopack root to the app directory for better workspace management.
- Modified package.json scripts to use Webpack during development and build processes.
- Refactored postcss.config.mjs to set the base path for Tailwind CSS.
- Replaced CSS imports in globals.css with Tailwind directives for better styling management.
- Introduced RotatingTetrahedronCanvas component for dynamic visual effects on the Welcome page.
- Revamped Welcome page layout to include the new canvas and improve overall design and user engagement.

* refactor: update CSS imports and enhance HeroCTA layout for improved responsiveness

- Replaced Tailwind CSS directives in globals.css with an import statement for better compatibility.
- Modified the HeroCTA component layout to improve responsiveness and alignment across different screen sizes.

* feat: integrate RotatingTetrahedronCanvas and update HeroCTA links for enhanced landing page experience

- Added RotatingTetrahedronCanvas component to display a dynamic 3D visual on the landing page.
- Replaced outdated links in HeroCTA component to direct users to the updated TinyHumans resources.

* update design
This commit is contained in:
Steven Enamakel
2026-03-20 17:07:04 -07:00
committed by GitHub
parent 8322006b61
commit 8bb1860ff7
17 changed files with 460 additions and 95 deletions
+41
View File
@@ -0,0 +1,41 @@
# Repository Guidelines
## Project Structure & Module Organization
- `src/`: React + TypeScript frontend (pages, components, hooks, store, services, lib).
- `src-tauri/`: Rust backend and Tauri desktop integration.
- `test/`: Vitest config and E2E/WebDriverIO setup (`test/e2e`, `test/wdio.conf.ts`).
- `skills/`: Skill runtime/build artifacts and manifests.
- `scripts/`: build/test automation (E2E helpers, tool generation).
- `docs/`: architecture and product documentation.
- `public/` and `src/assets/`: static assets.
## Build, Test, and Development Commands
- `yarn dev`: run Vite web dev server.
- `yarn dev:app` (or `yarn tauri:dev`): run desktop app with Tauri + TDLib bootstrap.
- `yarn build`: type-check and build web bundle.
- `yarn build:app`: build app bundle plus skills/tools generation.
- `yarn compile`: TypeScript check only (`tsc --noEmit`).
- `yarn test` / `yarn test:coverage`: run unit tests and coverage.
- `yarn test:rust`: run Rust tests in `src-tauri`.
- `yarn test:e2e`: run E2E suite (login/auth/payment/telegram/notion/gmail).
- `yarn lint` / `yarn lint:fix`, `yarn format:check` / `yarn format`: quality and formatting checks.
## Coding Style & Naming Conventions
- TypeScript-first; keep all app code under `src/`.
- Prettier is authoritative: 2 spaces, semicolons, single quotes, max width 100.
- Imports are auto-sorted via `@trivago/prettier-plugin-sort-imports`.
- ESLint (flat config) enforces React hooks rules, no duplicate imports, `prefer-const`, and TS-aware unused var checks.
- Naming: React components `PascalCase.tsx`; hooks `useX.ts`; slices/services/helpers `camelCase.ts`; tests `*.test.ts(x)`.
## Testing Guidelines
- Framework: Vitest + Testing Library (`jsdom`), with MSW utilities in `src/test/`.
- Unit tests live beside code (`__tests__`) or as `*.test.ts(x)` in `src/`.
- Coverage thresholds (global minimum): lines 15%, statements 15%, functions 15%, branches 12%.
- Run `yarn test:coverage` before opening non-trivial PRs.
## Commit & Pull Request Guidelines
- Prefer concise conventional-style subjects: `feat:`, `fix:`, `refactor:`, `docs:`, `chore:`.
- Keep commits scoped and descriptive (e.g., `fix: handle socket reconnect on auth expiry`).
- If contributing upstream, branch from `develop` and open PRs against `develop`.
- PRs should include: purpose, key changes, test evidence (commands run), linked issue (`Fixes #123`), and screenshots/videos for UI changes.
- Hooks exist but are lightweight; run lint, format, compile, and relevant tests manually before push.
+2 -2
View File
@@ -1,7 +1,7 @@
export default function Footer() {
return (
<footer className="border-t border-zinc-800 bg-zinc-950">
<div className="mx-auto max-w-7xl px-6 py-6 sm:px-8">
<footer className="border-t border-[var(--border-subtle)] bg-[#0c0c0c]">
<div className="w-full px-6 py-6 sm:px-8">
<div className="flex flex-wrap items-center justify-center gap-4 text-sm text-zinc-400">
<span>© {new Date().getFullYear()} OpenHuman</span>
<span className="text-zinc-600"></span>
+3 -20
View File
@@ -1,7 +1,6 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
import DownloadModal from './DownloadModal';
export default function HeroCTA() {
@@ -9,30 +8,14 @@ export default function HeroCTA() {
return (
<>
<div className="mt-10 flex items-center justify-center gap-4">
<div className="mt-10 flex justify-center">
<button
type="button"
onClick={() => setDownloadModalOpen(true)}
className="rounded-lg cursor-pointer bg-white px-6 py-3 text-sm font-semibold text-zinc-950 transition-colors hover:bg-zinc-200"
className="rounded-lg bg-[var(--accent)] px-6 py-2.5 text-sm font-semibold text-white shadow-none transition-colors hover:bg-[var(--accent-hover)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--accent)]"
>
Download 🔥
Download
</button>
<Link
href="https://x.com/openhumanxyz"
target="_blank"
rel="noopener noreferrer"
className="rounded-lg border border-zinc-800 px-6 py-3 text-sm font-semibold text-white transition-colors hover:border-zinc-700"
>
Join the Community
</Link>
<Link
href="https://openhuman.gitbook.io/docs"
target="_blank"
rel="noopener noreferrer"
className="rounded-lg border border-zinc-800 px-6 py-3 text-sm font-semibold text-white transition-colors hover:border-zinc-700"
>
Read the Docs
</Link>
</div>
<DownloadModal isOpen={downloadModalOpen} onClose={() => setDownloadModalOpen(false)} />
</>
+2 -2
View File
@@ -2,8 +2,8 @@ import Link from 'next/link';
export default function Navigation() {
return (
<nav className="fixed top-0 left-0 right-0 z-50 border-b border-zinc-800 bg-zinc-950/80 backdrop-blur-sm">
<div className="mx-auto max-w-7xl px-6 sm:px-8">
<nav className="fixed top-0 left-1/2 z-50 w-full max-w-[1280px] -translate-x-1/2 border-x border-b border-zinc-800 bg-zinc-950/80 backdrop-blur-sm">
<div className="px-6 sm:px-8">
<div className="flex h-16 items-center justify-between">
<Link href="/" className="text-xl font-semibold text-white">
OpenHuman
@@ -0,0 +1,111 @@
'use client';
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
import { ConvexGeometry } from 'three/addons/geometries/ConvexGeometry.js';
/** Canonical vertices of a truncated tetrahedron (permutations of 0, ±1, ±1). Convex hull = Archimedean solid. */
function truncatedTetrahedronPoints(scale: number): THREE.Vector3[] {
const coords: [number, number, number][] = [
[0, 1, 1],
[0, 1, -1],
[0, -1, 1],
[0, -1, -1],
[1, 0, 1],
[1, 0, -1],
[-1, 0, 1],
[-1, 0, -1],
[1, 1, 0],
[1, -1, 0],
[-1, 1, 0],
[-1, -1, 0],
];
return coords.map(([x, y, z]) => new THREE.Vector3(x, y, z).multiplyScalar(scale));
}
export default function RotatingTetrahedronCanvas() {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true,
powerPreference: 'high-performance',
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.NoToneMapping;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0.15, 4.8);
const geometry = new ConvexGeometry(truncatedTetrahedronPoints(0.92));
// Flat, panel-like read: matte off-white / reads as light vs shadow (Oblivion-style blocking).
const fillMaterial = new THREE.MeshLambertMaterial({
color: '#e4e4e4',
emissive: '#080808',
emissiveIntensity: 0.06,
});
const fillMesh = new THREE.Mesh(geometry, fillMaterial);
fillMesh.rotation.x = 0.35;
fillMesh.rotation.y = -0.45;
scene.add(fillMesh);
const ambientLight = new THREE.AmbientLight('#ffffff', 0.08);
const sun = new THREE.DirectionalLight('#ffffff', 1.35);
sun.position.set(4.5, 6, 5);
const bounce = new THREE.DirectionalLight('#8899aa', 0.22);
bounce.position.set(-3, -1, -2);
scene.add(ambientLight);
scene.add(sun);
scene.add(bounce);
let animationFrame = 0;
const resize = () => {
const parent = canvas.parentElement;
if (!parent) return;
const { width, height } = parent.getBoundingClientRect();
if (!width || !height) return;
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
const observer = new ResizeObserver(resize);
if (canvas.parentElement) observer.observe(canvas.parentElement);
resize();
const animate = () => {
fillMesh.rotation.y += 0.007;
fillMesh.rotation.x += 0.0045;
renderer.render(scene, camera);
animationFrame = window.requestAnimationFrame(animate);
};
animate();
return () => {
window.cancelAnimationFrame(animationFrame);
observer.disconnect();
geometry.dispose();
fillMaterial.dispose();
renderer.dispose();
};
}, []);
return (
<canvas ref={canvasRef} className="h-full w-full block" aria-label="Rotating tetrahedron" />
);
}
+1 -1
View File
@@ -55,7 +55,7 @@ export default function Downloads() {
return (
<div className="min-h-screen bg-zinc-950 text-white">
<Navigation />
<main className="mx-auto max-w-7xl px-6 pt-24 sm:px-8 sm:pt-32 pb-16">
<main className="w-full px-6 pt-24 sm:px-8 sm:pt-32 pb-16">
<div className="mx-auto max-w-4xl">
<h1 className="text-4xl font-bold tracking-tight sm:text-5xl">
Download for Free
+3 -3
View File
@@ -468,8 +468,8 @@ export default function FeedbackPage() {
return (
<div className="min-h-screen bg-zinc-950 text-white">
{/* Custom Header - Mobile Responsive */}
<header className="fixed top-0 left-0 right-0 z-50 border-b border-zinc-800 bg-zinc-950/80 backdrop-blur-sm">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<header className="fixed top-0 left-1/2 z-50 w-full max-w-[1280px] -translate-x-1/2 border-x border-b border-zinc-800 bg-zinc-950/80 backdrop-blur-sm">
<div className="px-4 sm:px-6 lg:px-8">
<div className="flex h-14 sm:h-16 items-center justify-between">
<div className="flex items-center gap-3 sm:gap-8">
<button
@@ -514,7 +514,7 @@ export default function FeedbackPage() {
</div>
</header>
<main className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 pt-20 sm:pt-24 pb-8">
<main className="w-full px-4 sm:px-6 lg:px-8 pt-20 sm:pt-24 pb-8">
<div className="flex gap-4 lg:gap-8">
{/* Mobile Sidebar Overlay */}
{sidebarOpen && (
+8 -2
View File
@@ -1,8 +1,14 @@
@import "tailwindcss";
:root {
--background: #09090b;
--background: #121212;
--foreground: #fafafa;
--surface: #1a1a1a;
--surface-raised: #242424;
--border-subtle: #2a2a2a;
--muted: #a1a1aa;
--accent: #4a83dd;
--accent-hover: #3d6fc7;
}
@theme inline {
@@ -15,5 +21,5 @@
body {
background: var(--background);
color: var(--foreground);
font-family: var(--font-geist-sans), Arial, Helvetica, sans-serif;
font-family: var(--font-geist-sans), system-ui, sans-serif;
}
+4 -4
View File
@@ -40,7 +40,7 @@ export default function RootLayout({
<link rel="manifest" href="/site.webmanifest" />
</head>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased flex min-h-screen flex-col`}
className={`${geistSans.variable} ${geistMono.variable} bg-[#121212] antialiased text-zinc-100`}
>
<Script
src="https://www.googletagmanager.com/gtag/js?id=G-VS26CY11RK"
@@ -54,10 +54,10 @@ export default function RootLayout({
gtag('config', 'G-VS26CY11RK');
`}
</Script>
<div className="flex-grow">
{children}
<div className="mx-auto flex min-h-[100dvh] w-full max-w-[1280px] flex-col border-x border-[var(--border-subtle)] bg-[#121212]">
<div className="flex flex-1 flex-col">{children}</div>
<Footer />
</div>
<Footer />
</body>
</html>
);
+64 -30
View File
@@ -1,43 +1,77 @@
import Link from 'next/link';
import HeroCTA from './components/HeroCTA';
import RotatingTetrahedronCanvas from './components/RotatingTetrahedronCanvas';
const connectLinks = [
{ label: 'X', href: 'https://x.com/tinyhumansai' },
{ label: 'GitHub', href: 'https://github.com/tinyhumansai/openhuman' },
];
export default function Home() {
return (
<div className="min-h-screen bg-black text-white relative">
<main className="mx-auto max-w-7xl px-6 sm:px-8 sm:pt-32 relative z-10">
<div className="mx-auto max-w-3xl text-center">
<img src="/android-chrome-192x192.png" alt="OpenHuman" className="w-[150px] h-[150px] mx-auto mb-4" />
<h1 className="text-5xl font-bold tracking-tight sm:text-6xl lg:text-7xl">
OpenHuman
</h1>
<p className="mt-6 text-lg leading-8 text-zinc-400 sm:text-xl">
Your AI superhuman for your personal and business life. In private beta.
</p>
<HeroCTA />
</div>
<div className="relative flex min-h-full flex-1 flex-col bg-[#121212] text-white">
<main className="relative z-10 w-full">
<section className="px-6 pb-12 pt-16 sm:px-10 sm:pb-16 sm:pt-20">
<div className="mx-auto max-w-xl text-center">
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-zinc-500">OpenHuman</p>
<div className="mx-auto mt-8 h-[min(200px,42vw)] w-[min(200px,42vw)] max-h-[220px] max-w-[220px]">
<RotatingTetrahedronCanvas />
</div>
<h1 className="mt-10 text-4xl font-bold tracking-tight text-white sm:text-5xl">Get started</h1>
<p className="mt-4 text-base leading-relaxed text-[var(--muted)] sm:text-lg">
Your AI superhuman for personal and business life. Private beta install the app and connect your
tools.
</p>
<HeroCTA />
</div>
</section>
<div className="mx-auto mt-24 max-w-5xl">
<div className="grid gap-8 sm:grid-cols-2 lg:grid-cols-3 text-center">
<div className="rounded-lg border border-zinc-800 bg-zinc-900/50 p-6">
<h3 className="text-lg font-semibold text-white">Large Scale Data Analysis</h3>
<p className="mt-2 text-sm text-zinc-400">
Analyze all your emails, messages, meeting notes and more. Control the chaos.
<section className="border-t border-[var(--border-subtle)]">
<div className="grid md:grid-cols-2">
<div className="border-b border-[var(--border-subtle)] px-6 py-12 sm:px-10 md:border-b-0 md:border-r md:border-[var(--border-subtle)]">
<h2 className="text-lg font-semibold tracking-tight text-white">Documentation</h2>
<p className="mt-2 max-w-sm text-sm leading-relaxed text-zinc-400">
Read the guides, learn how skills work, and explore what OpenHuman can do with your Telegram and
integrations.
</p>
<div className="mt-8 flex flex-wrap gap-3">
<a
href="https://tinyhumans.gitbook.io/openhuman"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center rounded-full bg-[var(--surface-raised)] px-4 py-2 text-sm font-medium text-zinc-200 ring-1 ring-zinc-700/80 transition-colors hover:bg-zinc-800 hover:text-white"
>
Read the docs
</a>
<Link
href="/downloads"
className="inline-flex items-center justify-center rounded-full bg-[var(--surface-raised)] px-4 py-2 text-sm font-medium text-zinc-200 ring-1 ring-zinc-700/80 transition-colors hover:bg-zinc-800 hover:text-white"
>
View downloads
</Link>
</div>
</div>
<div className="rounded-lg border border-zinc-800 bg-zinc-900/50 p-6">
<h3 className="text-lg font-semibold text-white text-center">Extreme Intelligence</h3>
<p className="mt-2 text-sm text-zinc-400">
Get insights from your data that you never thought possible.
</p>
</div>
<div className="rounded-lg border border-zinc-800 bg-zinc-900/50 p-6">
<h3 className="text-lg font-semibold text-white text-center">Take Action</h3>
<p className="mt-2 text-sm text-zinc-400">
Let OpenHuman do the heavy lifting. Automatically create tasks,
send messages, get reports, and more.
<div className="px-6 py-12 sm:px-10">
<h2 className="text-lg font-semibold tracking-tight text-white">Connect with us</h2>
<p className="mt-2 max-w-sm text-sm leading-relaxed text-zinc-400">
Follow updates, ship feedback, and join the community while we&apos;re in beta.
</p>
<div className="mt-8 flex flex-wrap gap-2">
{connectLinks.map(({ label, href }) => (
<a
key={href}
href={href}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center rounded-full bg-[var(--surface-raised)] px-4 py-2 text-sm font-medium text-zinc-200 ring-1 ring-zinc-700/80 transition-colors hover:bg-zinc-800 hover:text-white"
>
{label}
</a>
))}
</div>
</div>
</div>
</div>
</section>
</main>
</div>
);
+10 -2
View File
@@ -1,4 +1,9 @@
import type { NextConfig } from "next";
import type { NextConfig } from 'next';
import path from 'path';
import { fileURLToPath } from 'node:url';
// Pin Turbopack root to this app so a parent lockfile (e.g. ~/yarn.lock) is not chosen as the workspace root.
const landerRoot = path.dirname(fileURLToPath(import.meta.url));
// Enables static export so the landing site can be hosted on GitHub Pages.
// `NEXT_PUBLIC_BASE_PATH` is used so project pages can be deployed under `/${repo}`.
@@ -6,10 +11,13 @@ const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
const normalizedBasePath = basePath && basePath.trim().length > 0 ? basePath : undefined;
const nextConfig: NextConfig = {
output: "export",
output: 'export',
trailingSlash: true,
basePath: normalizedBasePath,
assetPrefix: normalizedBasePath,
turbopack: {
root: landerRoot,
},
};
export default nextConfig;
+2 -2
View File
@@ -3,8 +3,8 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"dev": "next dev --webpack",
"build": "next build --webpack",
"start": "next start",
"lint": "eslint"
},
+8 -1
View File
@@ -1,6 +1,13 @@
import path from 'path';
import { fileURLToPath } from 'node:url';
const landerRoot = path.dirname(fileURLToPath(import.meta.url));
const config = {
plugins: {
"@tailwindcss/postcss": {},
'@tailwindcss/postcss': {
base: landerRoot,
},
},
};
+2
View File
@@ -60,6 +60,7 @@
"@tauri-apps/plugin-os": "^2.3.2",
"@tauri-apps/plugin-shell": "~2",
"@types/react-router-dom": "^5.3.3",
"@types/three": "^0.183.1",
"buffer": "^6.0.3",
"debug": "^4.4.3",
"immer": "^11.1.3",
@@ -76,6 +77,7 @@
"redux-persist": "^6.0.0",
"socket.io-client": "^4.8.3",
"telegram": "^2.26.22",
"three": "^0.183.2",
"util": "^0.12.5",
"zustand": "^5.0.10"
},
@@ -0,0 +1,96 @@
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
const RotatingTetrahedronCanvas = () => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true,
powerPreference: 'high-performance',
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0, 4.6);
const fillMaterial = new THREE.MeshPhongMaterial({
color: '#7f5af0',
emissive: '#201040',
emissiveIntensity: 0.8,
shininess: 50,
transparent: true,
opacity: 0.65,
flatShading: true,
});
const wireMaterial = new THREE.MeshBasicMaterial({
color: '#a78bfa',
wireframe: true,
transparent: true,
opacity: 0.95,
});
const geometry = new THREE.TetrahedronGeometry(1.3, 0);
const fillMesh = new THREE.Mesh(geometry, fillMaterial);
const wireMesh = new THREE.Mesh(geometry, wireMaterial);
scene.add(fillMesh);
scene.add(wireMesh);
const ambientLight = new THREE.AmbientLight('#b4b1ff', 0.45);
const keyLight = new THREE.PointLight('#7f5af0', 1.2, 20);
keyLight.position.set(2.8, 2.5, 4);
scene.add(ambientLight);
scene.add(keyLight);
let animationFrame = 0;
const resize = () => {
const parent = canvas.parentElement;
if (!parent) return;
const { width, height } = parent.getBoundingClientRect();
if (!width || !height) return;
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
const observer = new ResizeObserver(resize);
if (canvas.parentElement) observer.observe(canvas.parentElement);
resize();
const animate = () => {
fillMesh.rotation.x += 0.006;
fillMesh.rotation.y += 0.009;
wireMesh.rotation.copy(fillMesh.rotation);
renderer.render(scene, camera);
animationFrame = window.requestAnimationFrame(animate);
};
animate();
return () => {
window.cancelAnimationFrame(animationFrame);
observer.disconnect();
geometry.dispose();
fillMaterial.dispose();
wireMaterial.dispose();
renderer.dispose();
};
}, []);
return <canvas ref={canvasRef} className="h-full w-full" aria-label="Rotating tetrahedron animation" />;
};
export default RotatingTetrahedronCanvas;
+50 -26
View File
@@ -1,39 +1,63 @@
import DownloadScreen from '../components/DownloadScreen';
import OAuthLoginSection from '../components/oauth/OAuthLoginSection';
import TypewriterGreeting from '../components/TypewriterGreeting';
import RotatingTetrahedronCanvas from '../components/RotatingTetrahedronCanvas';
interface WelcomeProps {
isWeb: boolean;
}
const Welcome = ({ isWeb }: WelcomeProps) => {
const greetings = ['Hello HAL9000! 👋', "Let's cook! 🔥", 'The A-Team is here! 👊'];
return (
<div className="min-h-full relative flex items-center justify-center">
{/* Main content */}
<div className="relative z-10 max-w-md w-full mx-4 space-y-6">
{/* Welcome card */}
<div className="glass rounded-3xl p-8 text-center animate-fade-up shadow-large">
{/* Greeting */}
<TypewriterGreeting greetings={greetings} />
<div className="min-h-full w-full bg-[#090b12] px-4 py-6 md:px-10 md:py-10">
<div className="mx-auto grid min-h-[calc(100vh-3.5rem)] w-full max-w-5xl grid-rows-[1fr_auto] border border-[#24293d] bg-[#0b0f18] text-white">
<section className="relative grid place-items-center border-b border-[#1e2335] px-6 py-14">
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_45%,rgba(127,90,240,0.14),transparent_55%)]" />
<p className="opacity-70 mb-8 leading-relaxed">
Welcome to AlphaHuman. Your Telegram assistant here to get you 10x more done in your
journey.
</p>
<p className="opacity-70 leading-relaxed">Are you ready for this?</p>
{/* Show OAuth login options in Tauri app, download screen on web */}
{!isWeb && (
<div className="mt-6">
<OAuthLoginSection />
<div className="relative z-10 flex w-full max-w-2xl flex-col items-center gap-7 text-center">
<div className="h-52 w-52 md:h-60 md:w-60">
<RotatingTetrahedronCanvas />
</div>
)}
</div>
{isWeb && <DownloadScreen />}
<h1 className="text-balance text-4xl font-semibold tracking-tight text-white md:text-6xl">
AlphaHuman
</h1>
<p className="max-w-xl text-sm text-[#8e96b8] md:text-base">
A focused command center for AI-driven execution. Minimal surfaces, hard edges, and
no visual noise.
</p>
<div className="flex flex-wrap items-center justify-center gap-3">
<button
className="border border-[#3d2f68] bg-[#201732] px-5 py-2 text-sm font-medium tracking-wide text-[#d4c8ff] transition-colors hover:bg-[#2a1d44]"
type="button">
{isWeb ? 'Download AlphaHuman' : 'Continue'}
</button>
<button
className="border border-[#2a3147] bg-[#121827] px-5 py-2 text-sm font-medium tracking-wide text-[#a7afce] transition-colors hover:bg-[#181f30]"
type="button">
View Docs
</button>
</div>
</div>
</section>
<section className="grid grid-cols-1 md:grid-cols-2">
<article className="border-b border-[#1e2335] p-6 md:border-b-0 md:border-r">
<p className="mb-2 text-xs uppercase tracking-[0.2em] text-[#7362b0]">Documentation</p>
<h2 className="text-2xl font-semibold tracking-tight">Built for depth</h2>
<p className="mt-2 max-w-sm text-sm text-[#8e96b8]">
Structured workflows, deliberate constraints, and precise outputs designed for power
users.
</p>
</article>
<article className="p-6">
<p className="mb-2 text-xs uppercase tracking-[0.2em] text-[#7362b0]">Connect</p>
<h2 className="text-2xl font-semibold tracking-tight">Join the mission</h2>
<p className="mt-2 max-w-sm text-sm text-[#8e96b8]">
Collaborate with the AlphaHuman community and shape what this assistant becomes next.
</p>
</article>
</section>
</div>
</div>
);
+53
View File
@@ -319,6 +319,11 @@
resolved "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz"
integrity sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==
"@dimforge/rapier3d-compat@~0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz#7b3365e1dfdc5cd957b45afe920b4ac06c7cd389"
integrity sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==
"@esbuild/aix-ppc64@0.27.2":
version "0.27.2"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz#521cbd968dcf362094034947f76fa1b18d2d403c"
@@ -1466,6 +1471,11 @@
minimatch "^9.0.0"
parse-imports-exports "^0.2.4"
"@tweenjs/tween.js@~23.1.3":
version "23.1.3"
resolved "https://registry.yarnpkg.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz#eff0245735c04a928bb19c026b58c2a56460539d"
integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==
"@types/aria-query@^5.0.1":
version "5.0.4"
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz"
@@ -1666,11 +1676,29 @@
resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
"@types/stats.js@*":
version "0.17.4"
resolved "https://registry.yarnpkg.com/@types/stats.js/-/stats.js-0.17.4.tgz#1933e5ff153a23c7664487833198d685c22e791e"
integrity sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==
"@types/statuses@^2.0.6":
version "2.0.6"
resolved "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz"
integrity sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==
"@types/three@^0.183.1":
version "0.183.1"
resolved "https://registry.yarnpkg.com/@types/three/-/three-0.183.1.tgz#d812d028b38ad68843725e3e7bd3268607cef150"
integrity sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==
dependencies:
"@dimforge/rapier3d-compat" "~0.12.0"
"@tweenjs/tween.js" "~23.1.3"
"@types/stats.js" "*"
"@types/webxr" ">=0.5.17"
"@webgpu/types" "*"
fflate "~0.8.2"
meshoptimizer "~1.0.1"
"@types/unist@*", "@types/unist@^3.0.0":
version "3.0.3"
resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz"
@@ -1686,6 +1714,11 @@
resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz"
integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
"@types/webxr@>=0.5.17":
version "0.5.24"
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.24.tgz#734d5d90dadc5809a53e422726c60337fa2f4a44"
integrity sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==
"@types/which@^2.0.1":
version "2.0.2"
resolved "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz"
@@ -2114,6 +2147,11 @@
dependencies:
"@wdio/logger" "9.18.0"
"@webgpu/types@*":
version "0.1.69"
resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.69.tgz#6b849bf370a1f29c78bd3aeba8e84c1150b237f2"
integrity sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==
"@xmldom/xmldom@^0.9.5":
version "0.9.8"
resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz"
@@ -4132,6 +4170,11 @@ fdir@^6.5.0:
resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz"
integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
fflate@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
figures@^6.1.0:
version "6.1.0"
resolved "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz"
@@ -5599,6 +5642,11 @@ merge2@^1.3.0:
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
meshoptimizer@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-1.0.1.tgz#c3ef0d509a8b84ac562493dba5a108fd67fa76dc"
integrity sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==
micromark-core-commonmark@^2.0.0:
version "2.0.3"
resolved "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz"
@@ -7709,6 +7757,11 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
three@^0.183.2:
version "0.183.2"
resolved "https://registry.yarnpkg.com/three/-/three-0.183.2.tgz#606e3195bf210ef8d1eaaca2ab8c59d92d2bbc18"
integrity sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==
timers-browserify@^2.0.4:
version "2.0.12"
resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz"