mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
The bar is Models, Dev, Platform, Pricing, Docs, Enterprise, Log in, and Get API key. The homepage is seven sections. Launch pages stay in the tree and drop out of the index through lib/launch.ts. /platform forwards to /cloud. Model and repository floors come from the snapshots the build already keeps. Co-authored-by: z <[email protected]>
179 lines
6.2 KiB
TypeScript
179 lines
6.2 KiB
TypeScript
'use client'
|
|
|
|
import { useRef } from 'react'
|
|
import Link from 'next/link'
|
|
import { ArrowRight } from 'lucide-react'
|
|
import { phrase } from '@hanzo/i18n'
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
import { Text, View, XStack, YStack } from '@hanzo/ui'
|
|
import { CREATIVE_MODELS } from '@/lib/creative-models'
|
|
import { NOW } from '@/lib/zen'
|
|
import { Section } from './chrome'
|
|
|
|
/**
|
|
* Every model, side by side and named as released (Zen 6, Kai 1, Koma 1): the
|
|
* language models (Enso, Kai, Zen) and the
|
|
* creative ones (Koma, Iro, Mori, Oto, Koe, Uta), each a panel that opens wide
|
|
* under the pointer onto its painting (public/images/models, painted on Hanzo's
|
|
* own engine), what it does in a line, and a link to its page, where its
|
|
* benchmarks are. The panel a reader points at opens; with
|
|
* none pointed at, Enso's stands open. Koma's panel plays its reel while open
|
|
* under the pointer. Below 1024px the panels are a row to swipe, every one open.
|
|
* The opening is CSS (`[data-models]` in app/layout.tsx), still under reduced
|
|
* motion. A model's name is said as released; what it is and what it does are
|
|
* authored (`phrase`) and drawn in the reader's language.
|
|
*/
|
|
|
|
interface Model {
|
|
slug: string
|
|
name: string
|
|
kind: string
|
|
line: string
|
|
href: string
|
|
still: string
|
|
}
|
|
|
|
const still = (slug: string) => `/images/models/${slug}.webp`
|
|
|
|
const LANGUAGE: readonly Model[] = [
|
|
{ slug: 'enso', name: 'Enso 1', kind: phrase('Router'), line: phrase('Each request goes to the model that answers it right for the least, across every frontier lab.'), href: '/enso', still: still('enso') },
|
|
{ slug: 'kai', name: 'Kai 1', kind: phrase('Decisions'), line: phrase('Deterministic probability distributions with sub-millisecond GPU latency and zero output tokens to pay for.'), href: '/kai', still: still('kai') },
|
|
{ slug: 'zen', name: NOW.name, kind: phrase('Open models'), line: phrase('Open-weight models for agentic coding. Download the weights or run them on Hanzo Cloud.'), href: '/zen', still: still('zen') },
|
|
]
|
|
|
|
const CREATIVE: readonly Model[] = CREATIVE_MODELS.map((m) => ({
|
|
slug: m.slug,
|
|
name: m.release,
|
|
kind: m.slug === 'oto' ? phrase('Sound') : m.modalityLabel,
|
|
line: m.lede,
|
|
href: `/${m.slug}`,
|
|
still: still(m.slug),
|
|
}))
|
|
|
|
const MODELS = [...LANGUAGE, ...CREATIVE]
|
|
const LEAD = 'enso'
|
|
|
|
/** Koma's reel, played while its panel is open under the pointer. */
|
|
function Reel({ still }: { still: string }) {
|
|
const ref = useRef<HTMLVideoElement>(null)
|
|
return (
|
|
<video
|
|
ref={ref}
|
|
data-media=""
|
|
muted
|
|
loop
|
|
playsInline
|
|
preload="none"
|
|
poster={still}
|
|
aria-hidden
|
|
onPointerEnter={() => void ref.current?.play().catch(() => {})}
|
|
onPointerLeave={() => ref.current?.pause()}
|
|
>
|
|
<source src="/videos/koma-demo.webm" type="video/webm" />
|
|
<source src="/videos/koma-demo.mp4" type="video/mp4" />
|
|
</video>
|
|
)
|
|
}
|
|
|
|
function Panel({ m }: { m: Model }) {
|
|
const { t } = useI18n()
|
|
const kind = t(m.kind)
|
|
return (
|
|
<View
|
|
data-model={m.slug}
|
|
data-lead={m.slug === LEAD ? '' : undefined}
|
|
render={<Link href={m.href} aria-label={t('{name}, {kind}', { name: m.name, kind })} />}
|
|
position="relative"
|
|
overflow="hidden"
|
|
rounded={20}
|
|
borderWidth={1}
|
|
borderColor="var(--border)"
|
|
bg="var(--pure-black)"
|
|
$platform-web={{ borderRadius: '20px', textDecoration: 'none' }}
|
|
>
|
|
{m.slug === 'koma' ? (
|
|
<Reel still={m.still} />
|
|
) : (
|
|
<View
|
|
data-media=""
|
|
render={<img src={m.still} alt="" loading="lazy" />}
|
|
position="absolute"
|
|
t={0}
|
|
l={0}
|
|
width="100%"
|
|
height="100%"
|
|
$platform-web={{ objectFit: 'cover' }}
|
|
/>
|
|
)}
|
|
<View
|
|
data-scrim=""
|
|
aria-hidden
|
|
position="absolute"
|
|
t={0}
|
|
l={0}
|
|
r={0}
|
|
b={0}
|
|
pointerEvents="none"
|
|
$platform-web={{ background: 'linear-gradient(to top, color-mix(in srgb, var(--pure-black) 82%, transparent) 0%, transparent 58%)' }}
|
|
/>
|
|
<Text
|
|
data-spine=""
|
|
aria-hidden
|
|
fontFamily="$mono"
|
|
fontSize="$2"
|
|
fontWeight="600"
|
|
color="var(--pure-white)"
|
|
position="absolute"
|
|
b={22}
|
|
l="50%"
|
|
$platform-web={{ transform: 'translateX(-50%) rotate(180deg)', writingMode: 'vertical-rl', whiteSpace: 'nowrap' }}
|
|
>
|
|
{m.name}
|
|
</Text>
|
|
<YStack data-open="" position="absolute" l={0} r={0} b={0} p={24} gap={8}>
|
|
<Text fontFamily="$mono" fontSize="$1" color="var(--white-80)">
|
|
{kind}
|
|
</Text>
|
|
<Text fontSize="$11" lineHeight="$11" fontWeight="600" color="var(--pure-white)" $platform-web={{ letterSpacing: '-0.035em' }}>
|
|
{m.name}
|
|
</Text>
|
|
<Text fontSize="$3" lineHeight="1.5rem" color="var(--white-80)" maxW={420}>
|
|
{t(m.line)}
|
|
</Text>
|
|
<XStack items="center" gap={6} mt={6}>
|
|
<Text fontSize="$2" fontWeight="600" color="var(--pure-white)">
|
|
{t('Explore {name}', { name: m.name })}
|
|
</Text>
|
|
<ArrowRight size={14} color="var(--pure-white)" aria-hidden data-i18n-mirror />
|
|
</XStack>
|
|
</YStack>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
/** Every model, the language ones alone (`language`), or the creative ones (`creative`, as /studio shows them). */
|
|
export default function Models({ creative, language }: { creative?: boolean; language?: boolean }) {
|
|
const { t } = useI18n()
|
|
const shown = creative ? CREATIVE : language ? LANGUAGE : MODELS
|
|
return (
|
|
<Section
|
|
id={creative ? 'creative' : 'models'}
|
|
label={creative ? 'Hanzo.Creative' : 'Hanzo.Models'}
|
|
title={t(creative ? 'Every creative model, in one studio.' : 'Every kind of model, one API.')}
|
|
lede={t(
|
|
creative
|
|
? 'Video, image, 3D, sound, voice and music, each a node on the canvas. Open one to see what it makes.'
|
|
: language
|
|
? 'Every model behind one key.'
|
|
: 'Language, routing, decisions and creative models. Open one to see what it does, and where it is measured.',
|
|
)}
|
|
>
|
|
<View data-models="" width="100%">
|
|
{shown.map((m) => (
|
|
<Panel key={m.slug} m={m} />
|
|
))}
|
|
</View>
|
|
</Section>
|
|
)
|
|
}
|