Files
zeekay a9cb4e5c51 models: the bento and every model page play the model's film
components/family/Film is the one player: the still is the first paint,
the loop is made only after hydration and only when motion is wanted, and
one IntersectionObserver for every film on the page loads a loop just
before it shows, plays it on screen and pauses it off. It fades in on
`playing`, so the step from still to loop cannot be seen.

The bento draws each card's film behind its words with no filter (the art
is grey already), a lighter scrim, the lean and a small grow on hover; the
line keeps to the left of the card and Enso runs its square master below
1024px. /enso, /kai, /zen and the six creative models open on Fold with the
film where a page puts its preview, screened onto the dot field and drawn
inverted in the light theme; Splash is that Fold with a model's words. The
route Enso takes and the decision Kai forms move to the band under it.

e2e/gates/films.spec.ts holds the files, their weight, the loops playing
and pausing, the phone's square Enso, reduced motion and each page's one
heading beside its film.
2026-10-30 07:49:49 -07:00

91 lines
4.1 KiB
TypeScript

import { expect, test } from '@playwright/test'
import { DESKS } from '../../components/zen/desks'
import { NEXT, NOW } from '../../lib/zen'
import { serveExport } from './export'
/**
* /ZEN TELLS THE WHOLE STORY, AND EVERY NUMBER ON IT HAS A SOURCE.
*
* The page opens on its painting and the release's name, then markets two
* releases, the one that answers and the research preview, each a card with its
* name large; every earlier Zen model is a link to its own page under /models.
* Then a run of short headlines, each with the content that backs it: the open
* lineage, the three machines Hanzo measured, what the board scored, and the
* one call that reaches it. Held
* at every width the site designs for, with motion on and with it off — a
* reduced-motion reader gets every word and every figure, finished.
*/
const WIDTHS = [375, 430, 768, 1024, 1440, 1728] as const
const HEADLINES = [
NOW.name,
NEXT.name,
`${NOW.name}.`,
'Laptop-sized.',
'On your desk.',
'Weights don',
'Seven generations. One line.',
'Scored where',
'Any SDK.',
'survive your vendor.',
] as const
test.describe('/zen', () => {
let base: string
let stop: () => Promise<void>
test.beforeAll(async () => {
const served = await serveExport()
base = served.url
stop = served.close
})
test.afterAll(async () => stop())
for (const width of WIDTHS) {
test(`at ${width}px it tells the story with nothing off the side`, async ({ page }) => {
const errors: string[] = []
page.on('pageerror', (e) => errors.push(String(e)))
page.on('console', (m) => m.type() === 'error' && errors.push(m.text()))
await page.setViewportSize({ width, height: 900 })
await page.goto(`${base}/zen`, { waitUntil: 'domcontentloaded' })
const heads = (await page.locator('h1, h2').allInnerTexts()).join(' \n ')
for (const h of HEADLINES) expect(heads, `a headline that says "${h}"`).toContain(h)
// The three machines, each with its two readings in tabular figures.
const desks = page.locator('#desks')
for (const d of DESKS) {
await expect(desks.getByRole('heading', { name: d.machine })).toBeVisible()
await expect(desks).toContainText(d.prefill)
await expect(desks).toContainText(d.decode)
}
const figure = desks.getByText(DESKS[0].prefill, { exact: true })
expect(await figure.evaluate((el) => getComputedStyle(el).fontVariantNumeric)).toContain('tabular-nums')
// No Hanzo score of the family is a research run yet, so none is printed; Zen 6 is not on a board either.
const scored = page.locator('#scored')
await expect(scored).toContainText('none is filed yet, so this page shows none')
await expect(scored).not.toContainText('GPQA-Diamond')
await expect(scored).toContainText(`${NOW.name} is not on the board yet`)
expect(await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth + 1)).toBe(false)
expect(errors, errors.join('\n')).toEqual([])
})
}
test('it opens on the release beside its film, and links every earlier model to its own page', async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 900 })
await page.goto(`${base}/zen`, { waitUntil: 'domcontentloaded' })
await expect(page.locator('h1')).toHaveText(NOW.name)
await expect(page.locator('section').first().locator('[data-film] img')).toHaveAttribute('src', '/models/zen.webp')
await expect(page.getByText('Open models. Yours to run.')).toBeVisible()
const now = page.locator('#now')
await expect(now.getByRole('heading', { name: NOW.name, exact: true })).toBeVisible()
await expect(now.getByRole('heading', { name: NEXT.name, exact: true })).toBeVisible()
const earlier = await now.locator('a[href^="/models/"]').evaluateAll((as) => as.map((a) => a.getAttribute('href')!))
expect(earlier.length).toBeGreaterThan(4)
for (const href of earlier) expect(href).toMatch(/^\/models\/[^/]+\/[^/]+$/)
// No section markets the earlier models one by one.
await expect(page.getByRole('heading', { name: /Every sense/ })).toHaveCount(0)
})
})