Some Tweaks for Mobile - #46
Conversation
* add meta tag for mobile * remove / on closing tag. HTML is not XML * shrink controls on small screens * set `<canvas>` to `display: block` rather than using `overflow: hidden` to hide the fact that `<canvas>` defaults to `display: inline` * use `height: 100%` instead of `height: 100vh` so it handles mobile hiding/removing bars. `100dvh` would also work.
|
Reviewed this with Claude Code. Merging — the viewport tag alone justifies the PR, and the The following are Claude's suggestions, not blockers. Recording them here so they don't get lost; I'll split them into follow-up issues. 1. The
|
|
you can probably ask claude to fix the mobile input. As for it's advice on the UI getting smaller, as it was, the padding made the UI fill a 1/4th of the screen on mobile. Adding a collapse bar might solve that. Just making the buttons smaller also solved it. The UI is not that complex so maybe small buttons are fine. |
|
@greggman thanks — you were right on the UI size, and I've taken the collapse-bar route. Reporting back on all of it. (Analysis and implementation by Claude, reviewed by me.) On the panel size: your objection was correctClaude's first pass kept the buttons at full size but spanned the panel edge-to-edge, which landed at the same ~1/4 of the screen you were complaining about — i.e. it would have reintroduced the problem your change was actually solving, while lecturing you about tap targets. Not a good trade. So: collapse bar, as you suggested. The panel folds behind a single button on small screens, which fixes the footprint without shrinking anything. Measured at 390x844:
Collapsed is a 44x44 button in the corner. That's a better footprint than the shrunk-button version and keeps full-size targets, so it's not a compromise between the two. It's CSS-only (checkbox + Mobile input: done
devicePixelRatio: done, and it needed more than the two lines I suggested
The part I'd missed when I wrote the original suggestion: the influence radius is in backing-store pixels too, so it needed to scale as well or the interaction would shrink on high-DPI screens. That needed a new uniform field — and while adding it I misread the existing Caught it, fixed it properly (uniform grew 32 → 48 bytes so Test coverage for the demoThe demo isn't in the regression suite and isn't shipped in the npm package, so nothing would have caught any of this. Added a shallow smoke test to It also probes that the module finished initializing by checking the mode button's label changes on click. Without that, a shader failure aborts the module before listeners are registered and every later check passes vacuously — which is exactly what the first draft of the test did. Verified both directions: green on the current tree, and red with the field-rename bug reintroduced, reporting both the shader error and the inert mode button. Docs (#47)Fixed separately. Root cause there was worse than the surface read: the article text wasn't just cramped, it was rendered entirely off-screen — Your |
Follow-ups to #46, which made the demo render correctly on a phone but left it non-functional there. Touch input. Interaction was bound to mousemove/mousedown/mouseup/ mouseleave. Mobile browsers synthesize a click from a tap but never a mousemove stream from a drag, so dragging did nothing and the shift-key repel was unreachable without a keyboard. Switched to pointer events with pointer capture, added touch-action:none to the canvas so the browser doesn't take the drag for scrolling, and added a Mode button that toggles pull/push. Shift-drag still inverts the mode for mouse users. devicePixelRatio. canvas.width was window.innerWidth with no DPR scaling. Before #46 the missing viewport tag meant innerWidth was the fake 980px layout viewport, which accidentally supersampled; with the viewport tag it became ~390 and the particles got blocky. Now scales by devicePixelRatio capped at 2. Pointer coordinates and the influence radius scale by the same factor, since the simulation works in backing-store pixels. The radius needed a new uniform. Note that the existing `padding` field in Params is not struct padding - it is the layout inset used by the sort and scan arrangements - so the uniform grew from 32 to 48 bytes to carry pointerRadius alongside it. The inset now scales with dpr too. Controls panel. #46 shrank the buttons to ~24px with a 0px gap to stop the panel eating a quarter of a phone screen. That fixed the footprint but made three buttons that each launch a slow GPU operation easy to mis-tap. Collapsed the panel behind a disclosure toggle instead, so the footprint problem is solved without shrinking anything: measured at 390x844, the panel is 1.1% of the screen collapsed and 21.1% open, with every tap target at 44px. CSS-only, because interactive_demo.mjs aborts early when WebGPU is missing and the panel should still fold away on the error screen. Benchmark plots. Observable Plot was hardcoded to width:1280, which overflows a phone. It now measures its container and clamps, falling back to 1280 where there's no DOM to measure. Added an overflow-x box around #plot as a safety net for anything still too wide. Verified in headless Chrome with WebGPU at 390x844 and 1440x900: no shader or console errors, canvas backing store 780x1688 and 2880x1800 respectively, zero page overflow, mode toggle works, render loop live across a synthesized touch drag, and the desktop layout unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Make the examples more mobile friendly