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.
This commit is contained in:
Steven Enamakel
2026-03-20 17:00:06 -07:00
parent 2ecc7cad22
commit 95aba8e3e6
3 changed files with 107 additions and 3 deletions
+2 -2
View File
@@ -18,7 +18,7 @@ export default function HeroCTA() {
Download 🔥
</button>
<Link
href="https://x.com/openhumanxyz"
href="https://x.com/tinyhumansai"
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"
@@ -26,7 +26,7 @@ export default function HeroCTA() {
Join the Community
</Link>
<Link
href="https://openhuman.gitbook.io/docs"
href="https://tinyhumans.gitbook.io/openhuman"
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"
@@ -0,0 +1,101 @@
'use client';
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
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.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.15;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0, 4.6);
// Subdivided tet + smooth normals ≈ Oblivion-style blunted / softened silhouette (not razor facets).
const geometry = new THREE.TetrahedronGeometry(1.35, 2);
geometry.computeVertexNormals();
const fillMaterial = new THREE.MeshPhysicalMaterial({
color: '#5b8fd9',
emissive: '#0d1f35',
emissiveIntensity: 0.45,
metalness: 0.42,
roughness: 0.18,
clearcoat: 0.92,
clearcoatRoughness: 0.12,
transparent: true,
opacity: 0.9,
flatShading: false,
});
const fillMesh = new THREE.Mesh(geometry, fillMaterial);
scene.add(fillMesh);
const ambientLight = new THREE.AmbientLight('#cbd5e1', 0.35);
const keyLight = new THREE.PointLight('#7ab4ff', 1.35, 24);
keyLight.position.set(2.8, 2.5, 4);
const rimLight = new THREE.PointLight('#4a83dd', 0.85, 18);
rimLight.position.set(-3.2, -1.2, 3.5);
const fillLight = new THREE.DirectionalLight('#e8f0ff', 0.55);
fillLight.position.set(-1.5, 2, 6);
scene.add(ambientLight);
scene.add(keyLight);
scene.add(rimLight);
scene.add(fillLight);
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;
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" />
);
}
+4 -1
View File
@@ -1,11 +1,14 @@
import HeroCTA from './components/HeroCTA';
import RotatingTetrahedronCanvas from './components/RotatingTetrahedronCanvas';
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" />
<div className="mx-auto mb-6 h-[180px] w-[180px] sm:h-[200px] sm:w-[200px]">
<RotatingTetrahedronCanvas />
</div>
<h1 className="text-5xl font-bold tracking-tight sm:text-6xl lg:text-7xl">
OpenHuman
</h1>