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

440 lines
20 KiB
TypeScript

'use client'
/**
* GPQA Diamond against what it costs: the accuracy-at-cost scatter /enso drew
* before its figures were read live (AccuracyCostScatter, removed in d0199249),
* drawn from the research API's runs when the page opens (lib/enso `field`).
* Up is accuracy, right is what 1,000 questions cost on a log axis. Each single
* model is its best run on the whole set, wearing its lab's mark on a plain disc;
* a published score is a dashed disc with its lab's mark, linking its source;
* Enso's tiers are ink discs wearing Hanzo's H (components/models/Maker). The
* frontier, the points no other beats on both, is computed and said in the alt
* text and each point's `data-front`, and not drawn (owner, 2026-10-17: "remove
* the line between dots"). What each point is (its set, its cost, its source)
* is in its tooltip and the alt text, not a legend.
*
* ONE PLOT, MEASURED TO ITS CARD. The SVG's user unit is a CSS pixel: the card's
* width is read (ResizeObserver) and the plot is laid out at exactly that width,
* so it fills the card at every size. Wide, it is 2.5 times as wide as tall
* (owner: "not so tall"), its type the token's 12px, a tick a rung of the
* one-three ladder; under PHONE px it is a little taller than wide, its type
* 11px and its discs smaller, a tick a decade. Labels are seated by `settle`,
* beside their dots, clear of every disc and label.
*
* Every colour is the page's ink or a token, so both themes draw it.
*
* A chart's axes do not turn on a right-to-left page: the plot is drawn left to
* right in every language (`direction` on the svg), and only its words are the
* reader's.
*/
import { useLayoutEffect, useRef, useState } from 'react'
import { typography } from '@hanzo/design'
import { phrase } from '@hanzo/i18n'
import { useI18n, type Say } from '@hanzo/i18n/react'
import { Ready } from '@/components/api/state'
import { Card } from '@/components/marketing/band'
import { Maker } from '@/components/models/Maker'
import { View } from '@/components/ui'
import { useEnso } from '@/hooks/useEnso'
import { LEAST, pct, short, usd, type Dot, type Field } from '@/lib/enso'
/** A rem token in CSS px, against the 16px root this site does not move; a token it cannot read stops the build here rather than drawing NaN. */
const unit = (rem: string) => {
const n = parseFloat(rem) * 16
if (!Number.isFinite(n)) throw new Error(`Chart: '${rem}' is not a length this chart can compute with`)
return n
}
/** Zen Mono's advance (0.6em) and the box a line of it is drawn in, measured for the scatter this replaces. */
const ADVANCE = 0.6
const RISE = 1.05
const DROP = 0.35
/** Daylight between a drawn edge and a label. */
const AIR = 2
/** Under this width, in px, the plot is the phone's; under LARGE, its type and discs are a step smaller. */
const PHONE = 600
const LARGE = 1000
/** The type: the label token at 12px, and 11px on a phone, never under. */
const TYPE = unit(typography['text-xs'])
const SMALL = TYPE - 1
/** How many lines a model's label may step away from its dot, with a leader, before it is left to the tooltip. */
const REACH = 2
/** How far, in px, a label keeps from a dot not its own that it sits level with or a leader passes. */
const CLEAR = 6
/** The discs: a model's, ours, our halo (the drawn edge), and the marks inside them. Ours stays the largest. */
type Disc = { r: number; ours: number; halo: number; mark: number; h: number }
type Geom = {
key: 'phone' | 'wide'
w: number
h: number
pad: { l: number; r: number; t: number; b: number }
type: number
disc: Disc
}
const clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), hi)
/** The plot for a card this wide: on a phone a little taller than wide, with decade ticks; above, 2.5 times as wide as tall. */
function geom(w: number): Geom {
return w < PHONE
? {
key: 'phone',
w,
h: clamp(Math.round(w * 1.3), 360, 560),
pad: { l: 28, r: 6, t: 26, b: 40 },
type: SMALL,
disc: { r: 8, ours: 10, halo: 13, mark: 11, h: 12 },
}
: {
key: 'wide',
w,
h: clamp(Math.round(w / 2.5), 380, 460),
pad: { l: 44, r: 20, t: 28, b: 44 },
// Under LARGE px the plot is as short and the points as close as a phone's: the phone's type, discs a step up.
type: w < LARGE ? SMALL : TYPE,
disc: w < LARGE ? { r: 9, ours: 11, halo: 14, mark: 12, h: 13 } : { r: 11, ours: 13, halo: 17, mark: 15, h: 15 },
}
}
/** The cost axis's rungs, dollars per 1,000 questions: a one-three ladder, and its decades. */
const LADDER = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 100, 300, 1000]
const DECADES = [0.01, 0.1, 1, 10, 100, 1000]
/** The extents and ticks the points need: accuracy from the five under the lowest to 100; price on a phone from the decade under the cheapest to the decade over the dearest, wide from a quarter under the cheapest to a quarter over the dearest, its ticks the ladder's rungs between. */
function axes(dots: Dot[], g: Geom) {
const lo = Math.max(0, Math.floor((Math.min(...dots.map((d) => d.accuracy * 100)) - 1) / 5) * 5)
const prices = dots.map((d) => d.cost).filter((p) => p > 0)
const [min, max] = [Math.min(...prices) / 1.25, Math.max(...prices) * 1.25]
// A phone's axis runs decade to decade; a wide one only as far as the points, so they spread over all of it.
const rungs = g.key === 'phone' ? DECADES : LADDER
const p0 = g.key === 'phone' ? ([...rungs].reverse().find((t) => t <= min) ?? rungs[0]) : min
const p1 = g.key === 'phone' ? (rungs.find((t) => t >= max) ?? rungs.at(-1)!) : max
return {
acc: { lo, ticks: Array.from({ length: (100 - lo) / 5 + 1 }, (_, i) => lo + i * 5) },
price: { lo: p0, hi: p1, ticks: rungs.filter((t) => t >= p0 && t <= p1) },
}
}
type Axes = ReturnType<typeof axes>
const xOf = (price: number, a: Axes, g: Geom) => {
const lo = Math.log(a.price.lo)
const t = (Math.log(clamp(price, a.price.lo, a.price.hi)) - lo) / (Math.log(a.price.hi) - lo)
return g.pad.l + t * (g.w - g.pad.l - g.pad.r)
}
const yOf = (acc: number, a: Axes, g: Geom) => g.h - g.pad.b - ((Math.min(acc, 100) - a.acc.lo) / (100 - a.acc.lo)) * (g.h - g.pad.t - g.pad.b)
type Rect = { x0: number; x1: number; y0: number; y1: number }
const overlaps = (a: Rect, b: Rect) => a.x0 < b.x1 && b.x0 < a.x1 && a.y0 < b.y1 && b.y0 < a.y1
/** A point placed: its centre, its label (empty when no seat is left), the label's left edge and baseline, and whether a leader joins them. */
type Placed = Dot & { cx: number; cy: number; head: string; x0: number; labelY: number; lead: boolean }
const edgeOf = (p: Dot, g: Geom) => (p.ours ? g.disc.halo : g.disc.r)
/** A glyph's advance: 0.6em, or the whole pixel a browser snaps a small size to (11px draws 7px a glyph, not 6.6). */
const advance = (g: Geom) => Math.max(g.type * ADVANCE, Math.round(g.type * ADVANCE))
const widthOf = (text: string, g: Geom) => text.length * advance(g)
function labelBox(text: string, x0: number, y: number, g: Geom): Rect {
return { x0, x1: x0 + widthOf(text, g), y0: y - g.type * RISE, y1: y + g.type * DROP }
}
function discBox(p: Placed, g: Geom): Rect {
const e = edgeOf(p, g) + 1
return { x0: p.cx - e, x1: p.cx + e, y0: p.cy - e, y1: p.cy + e }
}
/**
* Where a label may stand, nearest first: at `k` 0 beside its dot (east or west
* by the room there, then above, below and the four corners); at `k` 1 to
* REACH, `k` steps further out (up, down, across, or off a corner), joined to
* its dot by a leader.
*/
function seats(p: Placed, text: string, g: Geom, k: number): { x0: number; y: number }[] {
const w = widthOf(text, g)
const e = edgeOf(p, g)
const gap = e + AIR
const mid = p.cy + g.type * 0.35
const over = p.cy - e - AIR - g.type * DROP
const under = p.cy + e + AIR + g.type * RISE
const east = p.cx + gap
const west = p.cx - gap - w
const near = p.cx + gap + w <= g.w - g.pad.r
const sides = near ? [east, west] : [west, east]
const corners = [p.cx + e * 0.4, p.cx - e * 0.4 - w]
if (k === 0)
return [...sides.map((x0) => ({ x0, y: mid })), { x0: p.cx - w / 2, y: over }, { x0: p.cx - w / 2, y: under }, ...[over, under].flatMap((y) => corners.map((x0) => ({ x0, y })))]
const step = k * (g.type * (RISE + DROP) + AIR)
const across = k * g.type * 2
return [
...[mid + step, mid - step].flatMap((y) => sides.map((x0) => ({ x0, y }))),
...(near ? [east + across, west - across] : [west - across, east + across]).map((x0) => ({ x0, y: mid })),
{ x0: p.cx - w / 2, y: over - step },
{ x0: p.cx - w / 2, y: under + step },
...[over - step, under + step].flatMap((y) => corners.map((x0) => ({ x0, y }))),
]
}
/** Where a label was seated: its text, its left edge and baseline, and how many steps from its dot. */
type Seat = { head: string; x0: number; labelY: number; k: number }
/**
* Whether a label beside `p` sits level with another dot `q` instead: in `q`'s
* row (their heights overlap) and just across from it, or in its column and
* just over or under it, while not in `p`'s own row or column.
*/
function level(b: Rect, q: Placed, p: Placed, g: Geom): boolean {
const row = (d: Placed) => d.cy + edgeOf(d, g) > b.y0 && d.cy - edgeOf(d, g) < b.y1
const column = (d: Placed) => d.cx + edgeOf(d, g) > b.x0 && d.cx - edgeOf(d, g) < b.x1
const across = Math.max(b.x0 - q.cx, q.cx - b.x1, 0) - edgeOf(q, g)
const above = Math.max(b.y0 - q.cy, q.cy - b.y1, 0) - edgeOf(q, g)
return (row(q) && !row(p) && across < AIR + CLEAR) || (column(q) && !column(p) && above < AIR + CLEAR)
}
/** How far a box is from a point. */
const reach = (b: Rect, x: number, y: number) => Math.hypot(Math.max(b.x0 - x, 0, x - b.x1), Math.max(b.y0 - y, 0, y - b.y1))
/**
* Seats every label in one order: each takes the nearest free seat with its
* figure, else the nearest with its name alone (a model's, never ours: the
* figure is in its tooltip); a seat is free when it is inside the plot, clear
* of every disc, its own included, and every label seated before it; and,
* beside its dot, nearer it than any other, or, on a leader, beside no other
* dot, so no label reads as another's.
* Ours and the frontier's look to the ends of the plot and are always drawn;
* any other model's with no free seat within REACH lines is left to its
* tooltip, rather than drawn far from its dot, so no label is ever drawn on
* another thing or out of reach of its own dot.
*/
function seat(order: Placed[], g: Geom, discs: Rect[], full: (p: Placed) => string): Map<Placed, Seat | null> {
const out = new Map<Placed, Seat | null>()
const seated: Rect[] = []
for (const p of order) {
const texts = p.ours ? [full(p)] : [full(p), short(p.name)]
const fits = (text: string, x0: number, y: number, k: number) => {
const b = labelBox(text, x0, y, g)
const own = reach(b, p.cx, p.cy)
return (
b.x0 >= g.pad.l - 4 &&
b.x1 <= g.w - 2 &&
b.y0 >= g.pad.t - 8 &&
b.y1 <= g.h - g.pad.b - 2 &&
![...discs, ...seated].some((o) => overlaps(b, o)) &&
// Beside its dot, no other is nearer or level with it in another's row or column; off it on a leader, no other dot is beside it.
others.every((q) => (k === 0 ? reach(b, q.cx, q.cy) > own && !level(b, q, p, g) : reach(b, q.cx, q.cy) > edgeOf(q, g) + AIR + CLEAR))
)
}
const others = order.filter((q) => q !== p)
const far = p.ours || p.front ? Math.ceil((g.h - g.pad.t - g.pad.b) / (g.type * (RISE + DROP))) : REACH
let got: Seat | null = null
for (let k = 0; k <= far && !got; k++)
for (const text of texts) {
const s = seats(p, text, g, k).find((c) => fits(text, c.x0, c.y, k))
if (s) {
got = { head: text, x0: s.x0, labelY: s.y, k }
break
}
}
if (got) seated.push(labelBox(got.head, got.x0, got.labelY, g))
out.set(p, got)
}
return out
}
/**
* Seats the labels in a few orders (ours first, then the frontier's: by
* height, the most crowded first, right to left, left to right; and ours and
* the frontier's together, left to right and top down) and keeps the layout
* that drops the fewest labels, then moves ours least, then the frontier's,
* then drops the fewest figures, then stands the rest nearest.
*/
function settle(pts: Placed[], g: Geom, full: (p: Placed) => string): void {
const discs = pts.map((p) => discBox(p, g))
const crowd = (p: Placed) => pts.filter((q) => q !== p && Math.hypot(q.cx - p.cx, q.cy - p.cy) < 90).length
const rank = (by: (a: Placed, b: Placed) => number) =>
[...pts].sort((a, b) => Number(b.ours) - Number(a.ours) || Number(b.front) - Number(a.front) || by(a, b))
const lead = (by: (a: Placed, b: Placed) => number) => [...pts].sort((a, b) => Number(b.ours || b.front) - Number(a.ours || a.front) || by(a, b))
const orders = [
rank((a, b) => a.cy - b.cy),
rank((a, b) => crowd(b) - crowd(a) || a.cy - b.cy),
rank((a, b) => b.cx - a.cx),
rank((a, b) => a.cx - b.cx),
lead((a, b) => a.cx - b.cx),
lead((a, b) => a.cy - b.cy),
]
const weigh = (p: Placed) => (p.ours ? 1000 : p.front ? 100 : 10)
const cost = (m: Map<Placed, Seat | null>) =>
[...m.entries()].reduce((c, [p, s]) => c + (s ? (s.head === full(p) ? 0 : 100) + s.k * weigh(p) : 100_000), 0)
const best = orders.map((o) => seat(o, g, discs, full)).sort((a, b) => cost(a) - cost(b))[0]
for (const p of pts) {
const s = best.get(p)
Object.assign(p, s ? { head: s.head, x0: s.x0, labelY: s.labelY, lead: s.k > 0 } : { head: '' })
}
}
/** The leader from a dot's edge to the nearest point of its label's box. */
function leader(p: Placed, g: Geom): string {
const b = labelBox(p.head, p.x0, p.labelY, g)
const nx = clamp(p.cx, b.x0, b.x1)
const ny = clamp(p.cy, b.y0 - 1, b.y1 + 1)
const len = Math.hypot(nx - p.cx, ny - p.cy) || 1
const e = edgeOf(p, g)
return `${p.cx + ((nx - p.cx) / len) * e},${p.cy + ((ny - p.cy) / len) * e} ${nx},${ny}`
}
const MONO = 'var(--font-mono)'
const money = (v: number) => `$${v}`
const DASH = '3 2.5'
/** What a point is, in words, for its tooltip: its name and figure, its set or its source, and what it cost. */
function said(p: Dot, n: number, t: Say) {
const at = { name: p.name, score: pct(p.accuracy), cost: usd(p.cost) }
if (p.ours) return t('{name} at {cost} per 1,000, its cost on new questions: {score} · questions it has seen', at)
if (p.kind === 'reported')
return t('{name} {score} on GPQA Diamond, reported by {by}; {cost} per 1,000 questions estimated from its list price. {source}', { ...at, by: String(p.by), source: p.record })
return t('{name} {score}, a single model tested on the same {n} GPQA Diamond questions, {cost} per 1,000 of them', { ...at, n })
}
function Plot({ f, g }: { f: Field; g: Geom }) {
const { t } = useI18n()
const a = axes(f.dots, g)
const full = (p: Dot) => `${p.ours ? p.name : short(p.name)} ${pct(p.accuracy)}`
const placed: Placed[] = f.dots.map((d) => ({ ...d, cx: xOf(d.cost, a, g), cy: yOf(d.accuracy * 100, a, g), head: '', x0: 0, labelY: 0, lead: false }))
const at = new Map(placed.map((p) => [p.system, p]))
settle(placed, g, full)
const front = f.front.map((s) => at.get(s)!.name).join(', ')
const reported = f.dots.some((d) => d.kind === 'reported')
const half = (p: Dot) => (p.ours ? g.disc.h : g.disc.mark) / 2
const tick = (v: number) => Math.min(xOf(v, a, g), g.w - 2 - (money(v).length * advance(g)) / 2)
// The cost axis's words; the arrows point along the axis, which runs left to right in every language.
const per = t('$ per 1,000 questions')
const caption = g.key === 'phone' ? `${per} →` : `${t('cheaper')} ← ${per} → ${t('dearer')}`
const alt = [
t(
"GPQA Diamond accuracy against what 1,000 questions cost, on a log scale; models under {least}% are not drawn. Plain discs are single models tested on the same {n} questions, each at its best run and the cost it filed. Ink discs wearing Hanzo's H are Enso's tiers on questions it has seen, each at its tier's cost on new questions.",
{ least: Math.round(LEAST * 100), n: f.n },
),
reported
? t(
"Dashed discs are scores reported by a lab or an independent evaluation, each at its model's list price times the median tokens a question took in our runs of its lab's models, or of all of them.",
)
: null,
t('The frontier, the points no other beats on both accuracy and cost, is {front}.', { front }),
]
return (
<svg
viewBox={`0 0 ${g.w} ${g.h}`}
width={g.w}
height={g.h}
direction="ltr"
role="img"
aria-label={alt.filter(Boolean).join(' ')}
data-plot={g.key}
>
{a.acc.ticks.map((v) => (
<g key={`a${v}`}>
<line x1={g.pad.l} x2={g.w - g.pad.r} y1={yOf(v, a, g)} y2={yOf(v, a, g)} stroke="var(--border)" strokeWidth={1} />
<text x={g.pad.l - 8} y={yOf(v, a, g) + 4} textAnchor="end" fill="var(--muted-foreground)" fontSize={g.type} fontFamily={MONO}>
{v}
</text>
</g>
))}
{a.price.ticks.map((v) => (
<text key={`p${v}`} x={tick(v)} y={g.h - g.pad.b + 20} textAnchor="middle" fill="var(--muted-foreground)" fontSize={g.type} fontFamily={MONO}>
{money(v)}
</text>
))}
<text x={g.pad.l - 8} y={g.pad.t - 14} textAnchor="start" fill="var(--muted-foreground)" fontSize={g.type} fontFamily={MONO}>
GPQA Diamond %
</text>
<text x={g.w - g.pad.r} y={g.h - 6} textAnchor="end" fill="var(--muted-foreground)" fontSize={g.type} fontFamily={MONO}>
{caption}
</text>
{[...placed]
.sort((x, y) => Number(x.ours) - Number(y.ours))
.map((p) => {
const dot = (
<g key={p.system} data-dot={p.system} data-kind={p.ours ? 'ours' : p.kind} data-front={p.front ? '' : undefined}>
<title>{said(p, f.n, t)}</title>
{p.head && p.lead ? <polyline fill="none" stroke="var(--muted-foreground)" strokeOpacity={0.6} strokeWidth={1} points={leader(p, g)} /> : null}
{p.ours ? <circle cx={p.cx} cy={p.cy} r={g.disc.halo} fill="var(--foreground)" opacity={0.12} /> : null}
<circle
cx={p.cx}
cy={p.cy}
r={p.ours ? g.disc.ours : g.disc.r}
fill={p.ours ? 'var(--foreground)' : 'var(--background)'}
stroke={p.ours ? 'var(--foreground)' : 'var(--muted-foreground)'}
strokeWidth={1}
strokeDasharray={p.kind === 'reported' ? DASH : undefined}
/>
{p.ours || p.mark ? (
<foreignObject x={p.cx - half(p)} y={p.cy - half(p)} width={half(p) * 2} height={half(p) * 2} color={p.ours ? 'var(--background)' : 'var(--foreground)'}>
<Maker id={p.mark} ours={p.ours} size={half(p) * 2} />
</foreignObject>
) : null}
{p.head ? (
<text
x={p.x0}
y={p.labelY}
fontSize={g.type}
fontFamily={MONO}
fill={p.ours ? 'var(--foreground)' : 'var(--muted-foreground)'}
fontWeight={p.ours ? 700 : 400}
>
{p.head}
</text>
) : null}
</g>
)
return p.kind === 'reported' ? (
<a key={p.system} href={p.record} target="_blank" rel="noopener noreferrer">
{dot}
</a>
) : (
dot
)
})}
</svg>
)
}
/** The card's content width, read as it changes; 0 until it is measured. */
function useWidth() {
const ref = useRef<HTMLDivElement>(null)
const [w, setW] = useState(0)
useLayoutEffect(() => {
const el = ref.current
if (!el) return
const read = () => setW(Math.floor(el.getBoundingClientRect().width))
read()
const watch = new ResizeObserver(read)
watch.observe(el)
return () => watch.disconnect()
}, [])
return [ref, w] as const
}
/** The plot, laid out at its card's width once that is measured. */
function Sized({ f }: { f: Field }) {
const [ref, w] = useWidth()
return <div ref={ref}>{w > 0 ? <Plot f={f} g={geom(w)} /> : null}</div>
}
/**
* The chart in its card: once the runs and the price list are read; reading, or
* unreachable, until then. Not drawn while no Enso tier is on the frontier
* (lib/enso `field`).
*/
export function Chart() {
return (
<Ready reading={useEnso()} what={phrase("Enso's research runs")}>
{(e) =>
e.field ? (
<View width="100%" data-chart="gpqa">
<Card p="$3" $sm={{ p: '$5' }}>
<Sized f={e.field} />
</Card>
</View>
) : null
}
</Ready>
)
}