Skip to content

fix(canvas): size a canvas by layout and keep that size across re-renders - #78

Merged
SunkenInTime merged 1 commit into
masterfrom
fix/canvas-layout-size
Sep 6, 2026
Merged

SunkenInTime merged 1 commit into
masterfrom
fix/canvas-layout-size

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Sep 5, 2026 •

Copy link
Copy Markdown
Collaborator

What

<canvas class="w-0 grow h-[8px]"> painted nothing. weaver check passed, 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:

  1. SDK re-render clobber. updateCanvasBinding overwrote the layout-delivered size with the class-declared size on every re-render and redrew at 0 wide. The runtime refires onCanvasResize only 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.
  2. Runtime delivered layout only at the next dispatch. Native's syncModel runs at the start of dispatch/rebuild, never after the layout pass itself. A fixed-clock capture dispatches nothing after its first frame, so the canvas never learned its size. Now onFrame compares each canvas's laid-out size with what the tree last published and returns one .canvas_layout message when they differ; that dispatch's sync fires the resize and the same-view projection shows the redraw.

Also:

  • CanvasNeedsExplicitSize is retired from weaver check. Its own message admitted the silent zero; it was a patch over this defect. w-full, fractions, and grow now work on a canvas. Contract amended.
  • Capture receipts gain CanvasDrewForStaleLayout in warnings when 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

  • Draw log from the probe, master vs branch, across two clock ticks: 0, 181, 0, 183 → 0, 181, 181, 183. Full mechanism and probes in experiments/render-loop-cadence/CANVAS-LAYOUT-SIZE.md (not in this PR; it's the experiment folder on Dara's machine).
  • New SDK unit test: a canvas keeps its layout size across re-renders.
  • New capture smoke fixture test/fixtures/canvas-grow with a real PNG pixel probe (the suite previously had only pixelsDifferentFromClear, 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 test 119 passed. npm run test:capture passed. zig build test 88 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


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…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-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown

Greptile Summary

This 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 blocked

Live native capture could not run on this Linux host because the supported-platform runtime/zig-out/bin/weaver-widget executable is unavailable. Portable null-platform builds compile but do not publish that executable, and fixed-clock capture probes stopped before rendering with UnsupportedViewKind. Configure VMs

Confidence Score: 4/5

The 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. runtime/src/main.zig and the canvas-grow capture fixture should receive a supported-platform native capture run before using the full capture path as a release gate.

T-Rex T-Rex Logs

What T-Rex did

  • Before the change, the exact current regression fixture failed at sdk/test/reconciler.test.mjs:772; actual re-render draw size was [0,8], expected [181,8].
  • After the change, the exact targeted test passed under Node v24.20.0.
  • The runtime and reconciler code paths were exercised to validate that the reconciler records the resolved canvas size, redraws immediately, and preserves layout across renders.
  • The SDK lifecycle test that starts w-0 grow at [0,8], dispatches layout [181,8], and verifies the redraw passed without regressing to zero width.
  • The capture and blocker checks demonstrated that the stale-layout diagnostic is emitted into the capture, and a real CLI capture blocker is not executable due to a missing built binary.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "fix(canvas): size a canvas by layout and..." | Re-trigger Greptile

@SunkenInTime
SunkenInTime merged commit c7759ec into master Sep 6, 2026
9 checks passed
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