Oracle review of 7d45d36 plus a bug the review turned up.
**Remove `VirtualList`**
The windowed wrapper is gone from `@gpuix/react`. Windowing on the React side
is application state: pass `itemCount`, `estimatedItemHeight` and `windowStart`
to the host `<virtual-list>` and render only that slice.
A generic wrapper cannot know when to widen its own window. It moved `range`
only when the native list reported a new visible range, so growing `itemCount`
without a scroll left the extra rows unmounted forever. A filter does exactly
that. The todo example hit it immediately: switching from a 2-row view to a
6-row view painted 2 rows.
view-done ok
view-starred ok
view-inbox FAILED: "Ship it" never mounted
view-today ok
`VirtualList` was never published, so the pending
`.changeset/windowed-virtual-list.md` now describes the native `itemCount` plus
`windowStart` path instead. README and AGENTS.md carry a worked example and the
rule that no wrapper should come back.
**Review fixes**
`web:build` ran `bun run --cwd ../packages/native build:web`, a path that does
not exist once the folder is copied, while the README claimed nothing depended
on the repository. The script is gone. The browser renderer ships inside
`@gpuix/native`; `web.ts` explains the repository-only build in its failure
message.
`example-app/README.md` claimed `<virtual-list>` builds only visible rows. GPUI
builds only visible native rows, but React still mounts every child. Corrected.
`noImplicitAny: false` is dropped from the Quickstart tsconfig and from
`example-app/tsconfig.json`. The example passes under full `strict`, so the
starter should not hand out weaker checking.
The lockfile finding resolved itself: `examples/package.json` on main now
declares `cbor-x` and `msgpackr`, and `bun install` in a clean checkout of HEAD
produces no diff.
**Verified**
`packages/react` 302 tests pass. `example-app` typechecks under full strict,
lints clean, and all four filter views paint through the automation client.
Session: ses_fc1c928b0ffeeHIfdRpxtE0QaV
Installing the published packages and writing an app was not possible by
following the README. Three things blocked it.
**1. `key` failed on every GPUIX element**
error TS2322: Type '{ key: string; ... }' is not assignable to type 'Props'.
Property 'key' does not exist on type 'Props'.
Any list built with `.map()` broke on the first `tsc` run. `key` was expected
to arrive through `JSX.IntrinsicAttributes`, but TypeScript 5 ignores that
member for intrinsic elements. React's DOM types work only because
`DetailedHTMLProps` already carries `key`.
`key` now sits on `Props`, next to `ref`, and on `VirtualListShared`, the one
element prop type that does not extend `Props`. Verified with a probe over all
12 intrinsic elements plus `motion.div`, `VirtualList`, Select, Combobox and
Tooltip.
`jsx-dev-runtime.d.ts` also re-exported `jsx` and `jsxs` from
`react/jsx-dev-runtime`, which exports only `jsxDEV`. The declarations now
match `jsx-dev-runtime.js`.
Nothing caught this because Bun never typechecks and the build tsconfig
excludes `src/__tests__`. CI now runs `bun run typecheck` in `example-app`,
whose `app.tsx` maps a keyed list inside a `<virtual-list>`.
**2. A hello world installed 254 MB**
`@gpuix/native` packed all six platform binaries into the main tarball through
a `*.node` glob, on top of the six per-platform packages that
`optionalDependencies` already resolves.
node_modules 254M
|- @gpuix/native 185M <- all six, never loaded
|- @gpuix/native-darwin-arm64 23M <- the one that loads
|- @gpuix/react 544K
The glob is gone. `index.js` still resolves the platform package at runtime.
**3. The README never said how to install**
It opened with the architecture and the mutation protocol. There was no
`bun add` anywhere, and no mention of `jsxImportSource`, which is required:
without it TypeScript uses DOM types and `<virtual-list>`, `<markdown>`,
`<code>` and `style.hover` all fail.
A **Quickstart** now sits between the hero and Examples: install, tsconfig,
entry file, `bun --hot`, `bun build --compile`. Nothing was removed. The
Building section says up front that it is for working on GPUIX itself.
**example-app/**
A todo app to copy, in one file, using the Waku palette from `chat.tsx`.
| Script | What it does |
|---|---|
| `bun run dev` | `bun --hot app.tsx` |
| `bun run build` | standalone binary in `dist/todo` |
| `bun run web:build` | browser renderer, needs nightly Rust |
| `bun run web:dev` | browser bundle served with COOP/COEP |
| `bun run screenshot` | drives the app through the automation client |
| `bun run typecheck` | `tsc --noEmit` |
It shows `<virtual-list>`, a native `<input>`, `motion.div`, tinted `<svg>`,
native `hover` and `active`, and `testId` hooks. `scripts/screenshots.ts`
regenerates `docs/images/todo-app.png` from it.
Verified on all four paths: `bun --hot`, the 77 MB binary, the browser build at
`localhost:4188`, and a clean `typecheck`.
Two things worth remembering, both now in comments:
- the browser build embeds only IBM Plex Sans and Lilex, so `Helvetica` falls
back to a monospace and the family has to differ per target
- `maxWidth` on a `<virtual-list>` row does nothing; the list lays each row out
at list width, so the column cap goes one level in
`bun.lock` carries a few entries from unrelated in-flight work in `examples/`.
They are inert and prune on the next install.
Session: ses_fc1c928b0ffeeHIfdRpxtE0QaV