Skip to content

Progressive rendering for generative UI components #33

@jerelvelarde

Description

@jerelvelarde

Problem

Generative UI components lack smooth progressive rendering. The experience is jarring in two distinct ways:

1. WidgetRenderer (HTML/SVG) flickers during streaming

The WidgetRenderer streams content via postMessage, but every update replaces content.innerHTML wholesale (widget-renderer.tsx, bridge JS line 364). This destroys and recreates the entire DOM on each token, causing:

  • Visible flickering as elements are torn down and rebuilt
  • CSS animations re-trigger — the fadeSlideIn stagger animations on #content > * children (lines 305-319) restart on every update since the elements are new
  • No visual continuity — elements that were already rendered get replaced with identical copies

Compare this to Claude Artifacts, where SVG/HTML elements appear one by one with staggered fade-in animations. Once an element is on screen it stays stable — new elements are appended, not re-injected.

2. Structured React components render all-at-once

  • BarChart / PieChart — entire chart + legend appears in a single frame when data arrives from the agent
  • MeetingTimePicker — all time slots appear simultaneously

These components have no concept of streaming or progressive reveal.

Desired Behavior

WidgetRenderer:

  • Diff incoming HTML against current DOM instead of replacing innerHTML (or use a morphing library)
  • New top-level elements should fade/slide in individually as they stream in
  • Already-rendered elements should remain stable (no flicker, no animation restart)
  • Reference: Claude Artifacts progressive SVG rendering — elements appear one by one with stagger animation

Structured components (charts, pickers):

  • Animate data points / slices / slots appearing progressively
  • Or at minimum, use a staggered entrance animation when the component first mounts

Technical Notes

  • widget-renderer.tsx line 364: content.innerHTML = tmp.innerHTML is the root cause of flickering
  • FORM_STYLES_CSS lines 305-319 already define fadeSlideIn stagger animations — these would work correctly if elements were appended rather than replaced
  • A DOM-morphing approach (e.g. morphdom, idiomorph, or manual diffing) could preserve existing nodes while patching in new content
  • The 800ms debounce settle detection (htmlSettled) could remain as-is for "streaming complete" signaling

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions