Skip to content

fix(cards): pad streaming/reasoning preview to constant row count#146

Closed
esengine wants to merge 1 commit intomainfrom
fix/streaming-card-fixed-height
Closed

fix(cards): pad streaming/reasoning preview to constant row count#146
esengine wants to merge 1 commit intomainfrom
fix/streaming-card-fixed-height

Conversation

@esengine
Copy link
Copy Markdown
Owner

@esengine esengine commented May 3, 2026

Summary

Fixes the up-down screen jitter the user reported when a plan card is mid-execution and a streaming card renders alongside it.

Root cause

CardStream.tsx:9-23 defines isSettled:

  • Active plan card → not settled until every step is done/skipped
  • Live region is a prefix slice (cutoff = i; break in CardStream.tsx:28-34) — once a card is live, every card after it is live too

So during plan execution, the streaming card lives in the redraw region. Each stream chunk forces Ink to erase + reprint the entire live region.

That alone wouldn't jitter if the live region's total height were constant. But it isn't:

  • StreamingCard.tsx:39visible = visualLines.slice(-STREAMING_PREVIEW_LINES) — during the first wave of output, visible.length goes 1 → 2 → 3 → 4 across chunks
  • Card rendered height: header(1) + visible.length2 → 3 → 4 → 5 rows as the stream ramps
  • ReasoningCard.tsx:103-107 StreamingPreview has the same ramp shape

Each chunk during the ramp shifts every card above (PlanCard included) by 1 row → visible jitter.

Fix

Pad the preview region to STREAMING_PREVIEW_LINES (4) so the rendered height is constant 5 rows for the whole streaming lifetime. Empty 1-row <Box height={1} /> (consistent with the existing spacer pattern at ReasoningCard.tsx:39). CardBox's borderLeft keeps drawing the accent across pad rows.

Done state is untouched — that branch returns full <Markdown> body, ends up in Static, never redraws.

Test plan

  • npm run verify — 1829/1829 tests pass
  • CI green
  • Visual: trigger a plan with steps + observe streaming during execution. Plan card should sit still while stream chunks arrive (no up-down shift).

Related

User reported up-down screen jitter when a plan card is mid-execution
and a streaming card is rendering above (or below) it. Tracing through
CardStream.tsx: an active plan card with non-done steps is treated as
"unsettled" and pulls every later card into the live region, where
they redraw on every chunk.

The actual jitter source is StreamingCard's preview region: it slices
the last STREAMING_PREVIEW_LINES of streamed content, which means the
rendered height grows from 1 row → 4 rows during the first wave of
output, and similarly for ReasoningCard's StreamingPreview. Each chunk
that lands during that ramp changes the live region's total height by
one row — Ink moves the cursor differently between erase + reprint,
the user sees neighbouring cards (PlanCard included) shift up and
down.

Pad both previews to STREAMING_PREVIEW_LINES with empty 1-row Boxes,
so the rendered height stays constant at header + 4 = 5 rows for the
whole streaming lifetime. CardBox's borderLeft continues to render
the accent bar through pad rows. No effect on the done-state branch
which keeps a variable-height full Markdown render — that goes to
Static and never redraws.
@esengine
Copy link
Copy Markdown
Owner Author

esengine commented May 3, 2026

Superseded — the actual cause of the up-down jitter the user reported was the right-side sidebar panel showing during plan-approval (queued-only steps), not the streaming card height ramp. Fix coming in a separate PR.

@esengine esengine closed this May 3, 2026
@esengine esengine deleted the fix/streaming-card-fixed-height branch May 3, 2026 03:46
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