fix(canvas): size a canvas by layout and keep that size across re-renders - #78
Conversation
…ders A <canvas class="w-0 grow"> painted nothing, and weaver check, the snapshot, and the receipt all said ok. Three independent agents hit it and were steered into hardcoding pixel widths. Two defects combined: 1. The SDK seeded the canvas binding with its class-declared size and, on every re-render, overwrote the layout-delivered size with that declared size again, then redrew at 0 wide. The runtime refires onCanvasResize only when layout moves, so the size never came back. 2. The runtime published canvas layout to the SDK only inside Native's syncModel, which runs at the start of the next dispatch. A widget with nothing else to dispatch (every fixed-clock capture, a live widget before its first event) never learned its size at all. SDK: the declared size is the guess for the first draw only; once layout has sized the canvas a re-render keeps it. Runtime: a presented frame whose canvas layout disagrees with what the tree last published returns one .canvas_layout message, and that dispatch's sync fires the resize; the same-view projection shows the redraw without a rebuild. Check: CanvasNeedsExplicitSize is retired, it was a patch over this defect. Capture: a canvas whose commands were drawn for a stale layout is now named in warnings (CanvasDrewForStaleLayout) so the receipt explains what the pixels show. Receipts: sdk/test "a canvas keeps its layout size across re-renders"; test/fixtures/canvas-grow in the capture smoke with a real PNG pixel probe (0 accent pixels on master, 1436 here, before and after a re-render); experiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md for the draw logs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Greptile SummaryThis change keeps layout-sized canvases drawing at their resolved dimensions after component re-renders and adds capture diagnostics for drawings that no longer match final layout geometry. Focused SDK and CLI checks passed: the layout-sized canvas preserves its delivered width through re-renders, and a stale-layout warning written by the runtime is retained in the capture receipt. T-Rex validation blockedLive native capture could not run on this Linux host because the supported-platform Confidence Score: 4/5The exercised canvas sizing and receipt-warning behavior works as intended, with no validated defects remaining. The exact regression test failed on the parent revision and passed with this change, proving that resolved layout dimensions survive later re-renders. CLI receipt handling was also exercised with an emitted stale-layout warning. A live native capture could not render on the available Linux environment, so the runtime presentation path was compiled and inspected but not completed on a supported desktop platform. Files Needing Attention: No code changes require correction.
What T-Rex did
Reviews (1): Last reviewed commit: "fix(canvas): size a canvas by layout and..." | Re-trigger Greptile |
What
<canvas class="w-0 grow h-[8px]">painted nothing.weaver checkpassed, the snapshot showed correct bounds, the receipt said ok. Three independent agents in the render-loop cadence experiment hit it and "fixed" it by hardcoding pixel widths, which the contract told them to do.Two defects, both fixed here:
updateCanvasBindingoverwrote the layout-delivered size with the class-declared size on every re-render and redrew at 0 wide. The runtime refiresonCanvasResizeonly when layout changes, so the size never came back. Now the declared size is only the first-draw guess; once layout has sized the canvas, re-renders keep it.syncModelruns at the start ofdispatch/rebuild, never after the layout pass itself. A fixed-clock capture dispatches nothing after its first frame, so the canvas never learned its size. NowonFramecompares each canvas's laid-out size with what the tree last published and returns one.canvas_layoutmessage when they differ; that dispatch's sync fires the resize and the same-view projection shows the redraw.Also:
CanvasNeedsExplicitSizeis retired fromweaver check. Its own message admitted the silent zero; it was a patch over this defect.w-full, fractions, andgrownow work on a canvas. Contract amended.CanvasDrewForStaleLayoutinwarningswhen a canvas's last commands were drawn for a different layout than it now has. With the fix in place no correct widget reaches it; it is a tripwire. Plumbing verified end to end with a scratch build that fired it unconditionally.Receipts
0, 181, 0, 183→0, 181, 181, 183. Full mechanism and probes inexperiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md(not in this PR; it's the experiment folder on Dara's machine).a canvas keeps its layout size across re-renders.test/fixtures/canvas-growwith a real PNG pixel probe (the suite previously had onlypixelsDifferentFromClear, which cannot tell a bar from its dark surface). Same fixture on master: 0 accent pixels. Here: 1436, before and after a provider re-render.npm test119 passed.npm run test:capturepassed.zig build test88 passed, 1 skipped.Not verified
Live desktop behavior on screen. The code path is identical to capture's, and a live time-subscribed widget would hit the clobber on its first tick, but I did not get a screenshot of the window.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.