Skip to content

playground: go-ndarray v0.11.0; browser proof at dark@2x and on a phone - #37

Merged
tannevaled merged 3 commits into
mainfrom
playground-ndarray-v0.11.0
Oct 11, 2026
Merged

tannevaled merged 3 commits into
mainfrom
playground-ndarray-v0.11.0

Conversation

@tannevaled

@tannevaled tannevaled commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Bumps the playground to go-ndarray v0.11.0 and widens the browser proof to dark@2x and a phone viewport.

1. go-ndarray v0.9.1 -> v0.11.0

go get github.com/go-ndarray/ndarray@v0.11.0 && go mod tidy. No API break: the playground compiles unchanged, and locally (Go 1.27.2) gofmt, vet (native and js/wasm), go test -race, the 100% statement-coverage gate, the engine suite run as WebAssembly under node and the full browser proof (the three existing cases) all pass. The wasm grows from 13,323,797 to 13,914,229 bytes (3,467,883 -> 3,590,670 gzipped). No playground feature was added.

2. Browser proof: dark@2x and a phone

  • dark@2x runs every existing assertion.
  • phone: page.setViewport({width: 390, height: 844, deviceScaleFactor: 3, isMobile: true, hasTouch: true}), because headless --window-size cannot go that narrow. It runs every existing assertion too.
  • Every case now also checks first that the canvas fits the width asked for, that the page does not scroll horizontally, that the canvas backing store matches the device pixels, and that the app painted something other than the background. These checks compare against the requested width: on a mobile viewport Chrome widens innerWidth to follow overflowing content, so a check against innerWidth would pass on the very overflow it is meant to catch. The first negative control below found that.
  • A capture (loaded-*.png) is now written as soon as the page is ready, so a failing case still leaves a picture in the playground-captures CI artifact.

How each new case was shown to fail

These were run locally with headless Chrome and puppeteer-core 24.43.1 against the Hugo-built page. Each one used a throwaway copy of the driver kept outside the repository, and the copy was then discarded.

case break result
dark@2x emulate light while the case expects dark fails: dark@2x: the canvas follows the forced theme — false
phone inject #nd-canvas{width:500px !important} fails: the canvas fits the viewport width — 0..500 of 390 (the first version, which compared against innerWidth, failed only on the viewport-size check, because innerWidth had grown to 501)
phone paint the canvas with the background colour before the check fails: the app rendered something (non-background pixels) — 0 px

The phone case FAILS on the real page, and this PR does not fix it

On the unmodified page the phone case passes the fit and render checks, the theme check and the README-example checks. It then fails on:

light@3x phone: the table is painted as a heatmap (viridis end colours on screen) — 0 px

This is a real layout defect, not a test artefact. Below 860 px the app stacks its two columns inside a canvas whose height is the window height (body.pg{overflow:hidden}, so the page cannot scroll). On a 390x844 phone the canvas is 779 CSS px tall, and the fixed parts of the stacked layout need more than that. ndarrayRects() reports table: {h: 0}, so the heatmap gets no height. The code panel (y 698 + h 220) runs past the bottom of the canvas and under the status line, and the title is clipped to "gc". You can see all of this in the loaded-light-3x-phone.png capture.

There are two ways to fix it, and neither belongs in a library bump:

  • let the playground page scroll vertically on narrow screens. That change goes in layouts/_default/playground.html, which this PR does not touch.
  • redesign the narrow layout inside the app, e.g. share the height between the table and the code panel or drop some of the stats lines. That is a feature and a design choice.

So this PR stays red on browser proof (headless Chrome) until one of those fixes lands. The two commits are separate, so the bump can go in alone if that is preferred.

The fix (third commit)

The phone case was red because the layout really was broken on a phone, so this PR now fixes it:

  • State.MinHeight(w) is the least height the scene needs at a given width; side by side it is 0. It is measured from the layout rather than computed. The scene is laid out once at a tall height, and the table's share, the only part that grows, is replaced by six rows. That way it cannot drift from the layout.
  • The wasm host makes the canvas at least that tall, and the stage scrolls vertically (overflow-y:auto). Pointer coordinates already come from getBoundingClientRect, so they stay correct when the stage scrolls.
  • Narrow top bar: the title gets a row of its own above presets and reset. Before, it got 10 px.
  • The driver scrolls a widget into view before clicking it, as a visitor would, and re-reads where the canvas is.

TestMinHeightOnAPhone pins this down, and it fails with the old top bar (title 30 px of 1170).

Locally:

  • coverage is 100%;
  • the browser proof passes 215/215;
  • the phone heatmap shows 28,829 px of colour, where it showed 0.

The phone screenshot shows the full title, the presets row, and the heatmap below the summary.

🤖 Generated with Claude Code

tannevaled and others added 3 commits October 11, 2026 10:36
v0.11.0 compiles against the playground unchanged: vet (native and
js/wasm), the -race suite, 100% statement coverage, the engine suite as
WebAssembly and the browser proof all pass with no source change. The
wasm grows from 13,323,797 to 13,914,229 bytes (3,467,883 to 3,590,670
gzipped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two cases join light@1x, dark@1x and light@2x, each running every
existing assertion: dark@2x, and a phone set with page.setViewport
(390x844 CSS px, deviceScaleFactor 3, isMobile, hasTouch), since
headless --window-size cannot go that narrow.

Every case now also checks, before anything else, that the canvas fits
the width asked for (measured against that width: a mobile viewport
widens innerWidth to follow overflow), that the page does not scroll
horizontally, that the backing store matches the device pixels and that
the app painted something besides the background. A capture is taken as
soon as the page is ready, so a failure still leaves a picture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The phone case of the browser proof (390x844 at 3x) found the stacked
layout broken: the page cannot scroll, so the canvas was the 779 px
under the nav bar, less than the stacked layout needs. The table, the
only part that grows, got 0 px; the code panel ran under the status
line; beside the presets and reset the title got 10 px ("gc").

- State.MinHeight(w): the least height the scene needs at width w, 0
  side by side. Measured, not computed: the layout is laid out once at a
  tall height and the table's share replaced by six rows, so it cannot
  drift from the layout.
- The wasm host makes the canvas at least that tall, and the stage
  scrolls vertically (overflow-y:auto); pointer coordinates already come
  from getBoundingClientRect.
- Narrow, the title has a row of its own above presets and reset.
- The driver scrolls a widget into view before clicking it, as a
  visitor does, and re-reads where the canvas is.

TestMinHeightOnAPhone pins it, and fails with the old top bar (title
30 px of 1170). Locally: 100% coverage; browser proof 215/215, phone
heatmap 28829 px (was 0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 496814e into main Oct 11, 2026
7 checks passed
@tannevaled
tannevaled deleted the playground-ndarray-v0.11.0 branch October 11, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant