Skip to content

Disable delegated window composition so drags reach the screen as one frame - #323

Merged
dovvnloading merged 1 commit into
mainfrom
fix/webview2-composition
Aug 14, 2026
Merged

Disable delegated window composition so drags reach the screen as one frame#323
dovvnloading merged 1 commit into
mainfrom
fix/webview2-composition

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

Problem

While dragging a node in the desktop app, its connection line visibly steps out of sync with the node - most obvious on slow drags in the dark theme. Measurements taken inside the page consistently showed the line perfectly attached, and captured renderer frames looked correct too, yet the screen showed the lag. The reporter also observed that the light theme appears unaffected.

The explanation consistent with all of those observations sits below the renderer. Recent WebView2 builds hand independently-composited page layers to the Windows compositor to assemble into the final on-screen image. A node card being dragged is moved on its own layer, while the connection lines are redrawn into a different one, and Windows can apply the card's new position one display frame before the freshly drawn line arrives. Nothing inside the page can see this, which is why every internal measurement disagreed with the screen. The dark theme does not cause the problem: a thin bright line on a near-black background simply makes each one-frame misstep obvious, while the identical misstep is nearly invisible on the light theme.

Change

  • The desktop launcher disables delegated composition for the app's embedded browser, so the renderer assembles the complete frame itself before handing one finished image to Windows. The setting is appended in front of any browser arguments the user already set through the same environment variable, and runtimes that predate the feature ignore it harmlessly.
  • Reverts the stylesheet change from Keep node cards and connection lines on the same compositing path #322: telling the browser to promote more layers cannot help under this mechanism, it only increases the number of independently-composited surfaces.

Test plan

  • Launcher file passes a syntax check; production bundle rebuilds cleanly
  • On the affected machine, dark theme: relaunch the desktop app, drag a connected node slowly, and confirm the connection stays pinned to the node - the reporter's reproduction, requiring visual confirmation

… frame

Recent WebView2 builds hand independently-composited page layers to the
Windows compositor to assemble on screen. A node card being dragged
lives on its own such layer, while its connection lines are redrawn into
a different one, and Windows can apply the card's movement one display
frame before the freshly drawn connection arrives - the line visibly
steps out of sync with the node it is attached to. Everything measured
inside the renderer (layout geometry, frame captures) shows the two
perfectly attached, because the divergence happens below the renderer at
window composition; a thin bright line on the dark theme's near-black
background makes each misstep obvious while the same misstep is nearly
invisible on the light theme, which is why the report was dark-only.

The launcher now disables delegated composition for the app's WebView2
instance, making the renderer assemble the complete frame itself before
handing one finished image to Windows. The flag is appended in front of
any WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS the user already set and is
ignored by runtimes that predate the feature.

Also reverts the will-change stylesheet addition from #322: promoting
more layers cannot help under this mechanism and only increases the
number of independently-composited surfaces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dovvnloading
dovvnloading merged commit 0aed015 into main Aug 14, 2026
dovvnloading added a commit that referenced this pull request Aug 14, 2026
…lives (#324)

A full audit of every difference between the two themes established that
no code executes differently by theme - the connection-lag-while-
dragging artifact is present in both, and dark merely renders it
visibly. Three rendering-relevant asymmetries did that, and this change
removes each:

1. Connection stroke: dark painted a bright line on a near-black canvas
   at roughly 2.07:1 contrast, versus light's soft 1.68:1 - and at
   stroke-width 1.5 the line falls into the renderer's hairline
   anti-aliasing regime below about 67 percent zoom, whose stepping is
   visibly harsher for light-on-dark than dark-on-light. A dedicated
   per-theme stroke token now reproduces light's contrast ratio on the
   dark canvas (dark #444444; light keeps its #AFAFAF appearance),
   stroke-width goes to 2 to stay out of hairline mode, and
   geometricPrecision pins high-quality anti-aliasing.

2. Shadows: dark's alphas (0.40/0.45/0.55) were 2.2x denser than
   light's (0.18/0.203/0.248) - the only structural asymmetry in the
   entire token palette - crisping the dragged card's silhouette and
   amplifying any visible misstep. Dark now uses light's values.

3. Page root background: html/body/#root had no background of their
   own, so pre-paint clears resolved to the embedding window's backdrop
   instead of the theme's canvas color. The root now paints the theme's
   window color opaquely in both themes.

Also corrects the #323 composition flag, which the audit found never
reached the browser: pywebview's Windows backend passes its own
--disable-features switch and duplicate switches resolve last-one-wins,
so the flag was silently discarded. Both feature names now travel in
one merged list, so whichever list wins carries both.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
dovvnloading added a commit that referenced this pull request Aug 14, 2026
These three changes were attempts at the drag artifact that were not
confirmed to work before shipping, and the most recent one made things
worse: with #324 in place the connection lag became visible in the light
theme as well, where it had previously been unnoticeable.

The most likely cause of that regression is the composition flag. The
audit behind #324 established that the flag added in #323 never reached
the browser, because the window library passes a conflicting switch and
duplicate switches resolve last-one-wins. #324 corrected the delivery,
so disabling delegated composition took effect for the first time - and
it applies to both themes equally, which matches the report exactly. The
stroke width increase and the explicit high-quality smoothing hint in
the same change also affect both themes and cannot be ruled out.

This restores graphlink_desktop.py, styles.css and gl-vars-dev.css to
their state as of #321. The measured performance fixes in #319, #320 and
#321 are untouched.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@dovvnloading
dovvnloading deleted the fix/webview2-composition branch August 15, 2026 14:41
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