Skip to content

fix(renderer): make code entrance animation type line-by-line#724

Merged
wyuc merged 2 commits into
THU-MAIC:mainfrom
tongshu2023:fix/code-element-stagger-531
Jun 16, 2026
Merged

fix(renderer): make code entrance animation type line-by-line#724
wyuc merged 2 commits into
THU-MAIC:mainfrom
tongshu2023:fix/code-element-stagger-531

Conversation

@tongshu2023

Copy link
Copy Markdown
Contributor

Summary

Fixes #531 — the code element's entrance animation typed all lines simultaneously instead of line-by-line.

Root cause

Exactly the ordering issue the report hypothesized:

  1. First render: animStates is an empty Map (it was only populated via a setTimeout(..., 0) inside an effect).
  2. Every CodeLineRow therefore mounts with animState === undefinedisNewLine === falseuseState(!isNewLine || typingDelay === 0) latches mounted = true. The typingDelays map is also empty at this point, so every row gets typingDelay = 0.
  3. One tick later the states arrive, isNewLine flips to true for every row — but mounted is already latched true, so the delayed-mount path (setTimeout(() => setMounted(true), typingDelay)) is a no-op, and the mounted && isNewLine effect fires setTyping(true) for all rows in the same tick.

Fix

Compute the first-render 'typing' states synchronously in the useState initializer, so rows see their animState and cumulative typingDelay on the very first render: line 0 types immediately, each later row renders null until its stagger delay elapses. The effect now only handles subsequent line edits (inserted/replaced), with prevLinesRef seeded to the initial lines and the first effect run skipped.

Behavior note: previously, toggling animate false→true marked every line inserted (because prevLinesRef started empty). With the ref seeded, a toggle no longer replays the entrance — flagging in case that old behavior was intentional.

Scope note: packages/@maic/renderer/src/elements/code/BaseCodeElement.tsx has the identical first-render pattern, but #706 is currently rewriting that exact effect (prev-line map). To avoid conflicting with it, this PR only fixes the app copy; happy to port the same fix to the package copy once #706 lands.

Verification

  • Code-path trace above; tsc --noEmit, eslint, prettier --check all clean.
  • No component-level test added: vitest.config.ts only includes tests/**/*.test.ts in a node environment (no jsdom/RTL infrastructure for .tsx behavior tests). If you'd like one, I can propose a minimal jsdom setup in a separate PR.

🤖 Generated with Claude Code

…IC#531)

On first render animStates was an empty Map, populated only via a
setTimeout(0) effect. Every CodeLineRow therefore mounted with
animState undefined, latched mounted=true from its initial props, and
took the non-animated branch. When the states arrived one tick later,
every already-mounted row fired setTyping(true) in the same tick, so
all lines typed simultaneously - the delayed-mount stagger path was
unreachable on first paint.

Compute the first-render typing states synchronously in the useState
initializer so rows see their animState and typingDelay on the very
first render: line 0 types immediately, each later row stays unmounted
until its cumulative delay. The effect now only handles subsequent
line edits (inserted/replaced), with prevLinesRef seeded to the
initial lines.

Behavior note: previously, toggling animate from false to true marked
every line "inserted" (prevLinesRef started empty); now the ref is
seeded so a toggle does not replay the entrance - arguably the less
surprising behavior.

Fixes THU-MAIC#531

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@wyuc wyuc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Verified the code block now reveals line-by-line on first paint instead of all at once. Good call scoping this to the app copy to avoid colliding with #706's package rewrite. Thanks!

@wyuc wyuc merged commit 2f53fdb into THU-MAIC:main Jun 16, 2026
2 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.

[Bug]: Code element entrance animation starts typing on all lines at once instead of line-by-line

2 participants