Add revealRate reveal pacing to <Renderer> (#751)#752
Open
oakleaf wants to merge 2 commits into
Open
Conversation
OpenUI Lang renders progressively as the response arrives, so the arrival rate is the reveal pace. When the response arrives bursty or whole — a fast tool-call generation, or a transport that coalesces writes (serverless response streaming buffers small writes, CDNs re-clump) — the components pop in all at once instead of assembling. revealRate decouples paint from arrival: while isStreaming, the Renderer feeds the streaming parser a growing prefix of the response on a clock, so completed statements stay stable (the parser caches them) while the pending one fills in and the UI assembles the way it would over a smooth stream. The revealed length is count-based and never resets mid-stream, so a non-append-only DSL change (a new element growing the root's child-ref list) keeps typing forward instead of re-assembling from blank; the streaming parser reconciles the shifted prefix by statement id. Settled content and prefers-reduced-motion render immediately. Default off — fully backward compatible. Pure pacing math lives in reveal.ts (unit-tested); the rAF and reduced-motion glue lives in useRevealedResponse. Refs thesysdev#751 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive createStreamingParser with clock-paced growing prefixes (the exact
sequence the Renderer feeds it) and assert the tree genuinely assembles: the
root renders mid-stream, before every statement has completed, and the
completed-statement count is monotonic — a completed component is never
un-rendered ("never blanks"). The paced stream lands exactly where a fresh
full parse does. Uses a ref-list-first DSL so the string is non-monotonic,
the shape a naive prefix reveal would blank-and-rebuild on.
Refs thesysdev#751
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the reveal-pacing option proposed in #751.
Problem
<Renderer>renders progressively as the response arrives, so arrival rate is the reveal pace. When the DSL arrives bursty or whole — a fast tool-call generation, or a transport that coalesces writes (serverless response streaming buffers small writes, CDNs re-clump) — the components pop in all at once instead of assembling.Approach
A new
revealRateprop. WhileisStreaming, the Renderer feeds the streaming parser a growing prefix of the response on a clock, so completed statements stay stable (the parser already caches them) while the pending one fills in — the UI assembles the way it would over a smooth stream. It isn't fighting the parser; it'sset()used as designed, paced on a timer instead of on network arrival.revealRateomitted/falsekeeps the current behavior. Fully backward compatible.statementId.prefers-reduced-motionrender immediately.Structure
reveal.ts— pure pacing math (framework-free, unit-tested).hooks/useRevealedResponse.ts— thinrequestAnimationFrame+ reduced-motion glue.Renderer.tsx— newrevealRateprop, pacesresponsebeforeuseOpenUIState.api-reference/react-lang.mdxgains the prop + a "Reveal pacing" section.Tests
reveal.test.ts— the pacing math.reveal-integration.test.ts— drives the realcreateStreamingParserwith clock-paced prefixes and asserts the tree genuinely assembles (the root renders mid-stream, before every statement has completed) and never blanks a completed statement, landing exactly where a full parse does.test,typecheck,lint:check,format:check,build). No new dependencies.Happy to adjust the API shape (
reveal="smooth", different defaults, statement- vs char-granularity) to match your preference.Closes #751