Files
zeekay 0f5536b707 hanzo.ai reads in the reader's language, and Arabic right to left
Every word the landing, the header menus, the phone sheet, the footer,
the help corner and the way in (sign-in, sign-up, the reset, the
invitation, the callback, onboarding, the 404) write goes through
@hanzo/i18n's t(): one sentence is one message, its figures, names and
links arguments; copy written as data is phrase('…') where written and
t(label) where drawn. Plans, the chart, the API states and the lines
lib/kai and lib/enso build for the landing do the same.

Right to left: <html lang dir> is set before the first paint (the
package's bootScript first in the head); a figure, clock, range or
price outside a sentence is isolated; sides are logical gui props, the
layout's [data-join] corners logical, a bar grows from the start;
arrows along the line mirror (Onward for "words ->" links). The repo
dates read in the reader's language.

Gates select by slot, never by an English label (rtl, help). New gate
translated.spec.ts: in Arabic the landing at 1440 and 390, every menu
open, the phone sheet, sign-in, sign-up and the app signed in hold no
authored English, nothing scrolls sideways, every range is isolated;
French the same for English's commonest words. What another package
draws with no words prop is listed by name (@hanzo/ui's Footer label,
@hanzo/build's composer row and suggestions).

@hanzo/i18n 0.5.3 (the catalogs: 1,443 keys, every offered locale
complete), @hanzo/app 0.2.1 (the app's words). The link gate imports
the terms versions from @hanzo/app, the one SDK main now resolves.
2026-10-22 19:54:31 -07:00

96 lines
5.2 KiB
TypeScript

'use client'
import Link from 'next/link'
import { Bot, Brain, Coins, Cpu, Database, Network, Plug, ScanEye } from 'lucide-react'
import type { ReactNode } from 'react'
import { phrase } from '@hanzo/i18n'
import { useI18n } from '@hanzo/i18n/react'
import { Text, View, XStack, YStack } from '@hanzo/ui'
import { More } from '@hanzo/ui/marketing'
import { Section } from './chrome'
/**
* The unified AI stack every app and model runs on: the eight parts an agent
* is built from, in the order a builder meets them (the gateway, the agents,
* their tools, their memory, then compute, data, billing and observability),
* each with what it gives in three plain lines and a link to its page. The
* apps and the models have their own sections above, so it names neither.
*/
type Part = { icon: ReactNode; name: string; line: string; gives: readonly [string, string, string]; href: string }
const ICON = { size: 20, color: 'var(--foreground)', 'aria-hidden': true } as const
const PARTS: readonly Part[] = [
{ icon: <Network {...ICON} />, name: phrase('AI Gateway'), line: phrase('Every model behind one key.'), gives: [phrase('One OpenAI-compatible API'), phrase('Routing across every frontier lab'), phrase('Spend limits and usage per key')], href: '/gateway' },
{ icon: <Bot {...ICON} />, name: phrase('Agents'), line: phrase('Agents that do the work, not just the chat.'), gives: [phrase('Background and scheduled runs'), phrase('Sandboxed runtimes'), phrase('Your tools and data, with your permissions')], href: '/agents' },
{ icon: <Plug {...ICON} />, name: 'MCP', line: phrase('The tools your agents act with.'), gives: [phrase('Search, files, shell and browser'), phrase('Works with any MCP client'), phrase('Bring your own MCP servers')], href: '/mcp' },
{ icon: <Brain {...ICON} />, name: phrase('Memory and Search'), line: phrase('What your agents know, and how they find it.'), gives: [phrase('Keyword and meaning in one query'), phrase('A knowledge graph for every org'), phrase('Retrieval over your documents')], href: '/search' },
{ icon: <Cpu {...ICON} />, name: phrase('Compute'), line: phrase('GPUs and machines, in our cloud or yours.'), gives: [phrase('GPUs for inference and training'), phrase('Containers and functions'), phrase('The same stack in your own cloud')], href: '/machines' },
{ icon: <Database {...ICON} />, name: phrase('Data'), line: phrase('A database for every org, ready to build on.'), gives: [phrase('SQL with live updates'), phrase('Files on S3-compatible storage'), phrase('Analytics over every event')], href: '/base' },
{ icon: <Coins {...ICON} />, name: phrase('Commerce'), line: phrase('Charge for what your agents do.'), gives: [phrase('Plans, subscriptions and top-ups'), phrase('Usage metered as it happens'), phrase('Invoices and payouts')], href: '/commerce' },
{ icon: <ScanEye {...ICON} />, name: phrase('Observability'), line: phrase('See every model call, end to end.'), gives: [phrase('Traces of every call'), phrase('Cost and latency per request'), phrase('Logs and metrics in one place')], href: '/o11y' },
]
function Card({ p }: { p: Part }) {
const { t } = useI18n()
return (
<YStack
render={<Link href={p.href} />}
gap={14}
p={20}
rounded={20}
borderWidth={1}
borderColor="var(--border)"
bg="$panel"
hoverStyle={{ borderColor: 'var(--border-strong)' }}
$md={{ p: 24 }}
$platform-web={{ borderRadius: '20px', textDecoration: 'none' }}
>
<View width={40} height={40} rounded={12} items="center" justify="center" borderWidth={1} borderColor="var(--border)" $platform-web={{ borderRadius: '12px' }}>
{p.icon}
</View>
<YStack gap={6}>
<Text fontSize="$5" lineHeight="$5" fontWeight="600" color="var(--foreground)">
{t(p.name)}
</Text>
<Text fontSize="$3" lineHeight="$4" color="var(--muted-foreground)">
{t(p.line)}
</Text>
</YStack>
<YStack gap={8} pt={12} borderTopWidth={1} borderColor="var(--white-06)">
{p.gives.map((g) => (
<XStack key={g} gap={10} items="flex-start">
<View width={5} height={5} mt={8} shrink={0} rounded={9999} bg="var(--foreground)" $platform-web={{ borderRadius: '9999px' }} />
<Text fontSize="$2" lineHeight="$3" color="var(--foreground)">
{t(g)}
</Text>
</XStack>
))}
</YStack>
</YStack>
)
}
export default function Platform() {
const { t } = useI18n()
return (
<Section
id="platform"
label="Hanzo.Stack"
title={t('The unified AI stack.')}
lede={t('Everything an agent needs, from the first model call to the invoice: one API, one sign-in, one bill. Every part is yours to build on directly.')}
>
<View display="grid" width="100%" gap={12} gridTemplateColumns="minmax(0, 1fr)" $sm={{ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))' }} $lg={{ gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 16 }}>
{PARTS.map((p) => (
<Card key={p.name} p={p} />
))}
</View>
<XStack gap={24} flexWrap="wrap">
<More href="/platform">{t('How the platform fits together')}</More>
<More href="/cloud">{t('Run it in your cloud')}</More>
</XStack>
</Section>
)
}