Add manual frame rendering API for environments without requestAnimationFrame#3521
Add manual frame rendering API for environments without requestAnimationFrame#3521mattgperry wants to merge 11 commits intomainfrom
Conversation
Code Review - PR #3521: Manual Frame Rendering APII've completed a thorough review of this pull request. Overall, this is a well-designed and well-tested addition that addresses a legitimate need for manual frame control in non-browser environments. Here's my detailed feedback: ✅ Strengths1. Well-Designed APIThe API is intuitive and flexible with multiple input modes:
The three-tier API ( 2. Excellent Test CoverageThe test file (
This follows the CLAUDE.md guideline of writing tests first. 3. Good Integration with Existing Systems
4. DocumentationExcellent JSDoc comments with multiple usage examples for Remotion, WebXR, and custom loops. 🐛 Issues & Concerns1. Potential Race Condition in
|
Pull Request ReviewOverviewThis PR adds a manual frame rendering API for environments without ✅ Strengths1. Strong API Design
2. Excellent Test CoverageThe test suite in
3. Documentation
🔍 Issues Found1. Potential Race Condition in
|
Pull Request Review: Manual Frame Rendering APII've completed a thorough review of PR #3521. This is a well-designed feature that adds manual frame control for environments without ✅ StrengthsArchitecture & Design
Code Quality
🔍 Issues & Recommendations1. Potential Race Condition in
|
| Category | Rating | Notes |
|---|---|---|
| Code Quality | ⭐⭐⭐⭐⭐ | Clean, well-structured, follows conventions |
| Test Coverage | ⭐⭐⭐⭐☆ | Comprehensive, but missing some edge cases |
| Documentation | ⭐⭐⭐⭐⭐ | Excellent examples and JSDoc |
| Performance | ⭐⭐⭐⭐⭐ | Minimal overhead, efficient implementation |
| Security | ⭐⭐⭐⭐⭐ | No concerns |
| Architecture | ⭐⭐⭐⭐⭐ | Excellent separation of concerns |
Overall: This is a high-quality PR that solves a real problem (Remotion/WebXR integration) with a clean, well-tested API. The issues identified are minor and mostly about edge cases and error handling.
✅ Recommended Actions Before Merge
- MUST: Add try-finally to
renderFrame(issue adding circleci config #4) - SHOULD: Add explicit return type to
processFrame(issue Add motionValue prop #3) - SHOULD: Add edge case tests (issue Adding
useViewportScroll#7) - CONSIDER: Review backward scrubbing delta behavior (issue Initial API (WIP) #1)
- CONSIDER: Document the
renderFrame({})behavior (issue Initial event setup #5) - VERIFY: Exports are available from
motion/react(issue Feature/frame #6)
Great work on this feature! 🎉
Pull Request Review: Manual Frame Rendering APISummaryThis PR adds comprehensive support for manual frame rendering in environments without requestAnimationFrame (WebXR, Remotion, SSR). The implementation is well-architected and includes a new StrengthsArchitecture & Design
Code Quality
Performance Considerations
Issues & Suggestions1. Critical: Type Safety Issue in
|
733eaa1 to
6f6b7ce
Compare
Pull Request Review: Manual Frame Rendering APISummaryThis PR adds comprehensive support for manually advancing animations in environments without ✅ Strengths1. Excellent Architecture
2. Comprehensive Test Coverage
3. Performance Considerations
4. Proper WAAPI Handling
🐛 Potential Issues1. Frame Cache Memory Leak Risk (packages/motion-dom/src/render/frame-cache.ts)Severity: Medium The frame cache uses Recommendation: // Add a maximum cache size or LRU eviction
const MAX_CACHED_FRAMES = 100
// Or document that users should call clearFrameCache() periodicallyLocation: packages/motion-dom/src/render/frame-cache.ts:9-14 2. Missing
|
PR Review: Manual Frame Rendering APIOverall Assessment: This is a well-architected feature that adds crucial functionality for non-requestAnimationFrame environments. The implementation is solid with excellent test coverage. I've identified some areas for improvement around edge cases, performance optimizations, and API design. ✅ Strengths1. Architecture & Design
2. Test Coverage
3. Documentation
🔴 Critical Issues1. Frame Cache Memory Leak Riskpackages/motion-dom/src/render/frame-cache.ts:1888 The frame cache uses Map<number, WeakMap<Element, ElementStyles>> but the outer Map with frame numbers will grow unbounded in long-running Remotion renders. Impact: A 5-minute video at 60fps = 18,000 Map entries. Each entry is small but the Map overhead adds up. Question: Is the frame cache needed during sequential forward rendering (typical video export)? Or only when scrubbing? If only for scrubbing, consider disabling during export. 2. Race Condition: Driver Setup Timingpackages/motion-remotion/src/MotionRemotion.tsx:2258 useInsertionEffect sets the driver, but child animations may start before the first renderFrame() call. Scenario:
3. Delta Calculation Inconsistencypackages/motion-remotion/src/MotionRemotion.tsx:2276 Delta calculation breaks when frames jump backward (scrubbing) or skip frames. Problem cases:
Recommendation: Document clearly that this is export-only, not for interactive scrubbing.
|
| Category | Status |
|---|---|
| Code Quality | ⭐⭐⭐⭐ (Very Good) |
| Test Coverage | ⭐⭐⭐⭐⭐ (Excellent) |
| Performance | ⭐⭐⭐⭐ (Good, with caveats) |
| Security | ⭐⭐⭐⭐⭐ (No concerns) |
| Documentation | ⭐⭐⭐⭐ (Very Good) |
Recommended Actions Before Merge:
- Critical: Address frame cache memory growth (Issue 1)
- Critical: Fix driver initialization race condition (Issue 2)
- Important: Document backward scrubbing limitations (Issue 3)
- Important: Fix test cleanup (Issue 4)
Nice to Have:
- Type safety improvements (Issue 5)
- Performance micro-optimizations (Issues 6, 7)
- Additional E2E tests (Suggestion 9)
Great work on this feature! The architecture is sound and the implementation is thorough. The issues identified are mostly edge cases and optimizations rather than fundamental problems. With the critical issues addressed, this will be a solid addition to the library.
PR Review: Manual Frame Rendering APIThis is an impressive and well-architected addition that enables Motion to work in non-rAF environments like Remotion, WebXR, and server-side rendering. The implementation is clean, the tests are comprehensive, and it follows the existing codebase patterns well. ✅ StrengthsArchitecture & Design
Code Quality
Implementation Details
🔍 Issues & Concerns1. Critical: Comment Syntax Error in JSAnimation.tsLine 402 has a single Fix needed: Change 2. Logic Issue: Restarting Finished AnimationsThe code at JSAnimation.ts:237-240 transitions finished animations back to "running" when scrubbing backwards with a custom driver. Concern: This mutates animation state in the sample method, which feels fragile. It's not clear this handles all edge cases like animations with repeat that finished multiple iterations. Recommendation: Add a comment explaining this behavior is specifically for backward scrubbing, and consider adding tests for edge cases. 3. Frame Cache Memory ManagementWhile WeakMaps prevent element-based leaks, the Scenario: A long Remotion video at 60fps for 5 minutes = 18,000 frames cached. Recommendation: Consider LRU cache, periodic cleanup, or document that users should call 4. Delta Calculation in MotionRemotion ComponentThe delta calculation (MotionRemotion.tsx:41-44) is based on frame jump, but Remotion can scrub non-sequentially. Recommendation: Clarify in comments whether delta should represent time between renders (current) vs time that passed in the animation timeline. 5. setCurrentFrame Global StateThe global mutable state in frame-cache.ts could cause issues with concurrent animations or React 18 concurrent rendering. Recommendation: Document that this is designed for single-composition rendering. 🎯 Minor Suggestions
📝 SummaryThis is high-quality work that solves a real problem elegantly. Must fix before merge:
Should fix before merge:
Consider for follow-up:
Overall: Recommend merge after fixing the syntax error and addressing frame cache concerns. Great work! The driver abstraction is elegant and sets up nice foundations for future timing contexts. Review by Claude Code |
Code Review: Manual Frame Rendering APIOverviewThis PR adds support for manually advancing animations in environments without requestAnimationFrame (WebXR, Remotion, SSR). The implementation is well-structured and addresses a real need (fixes #2496). ✅ StrengthsArchitecture & Design
Code Quality
🔍 Issues & Concerns1. CRITICAL: Potential Memory Leak in Frame CacheLocation: The frame cache uses Recommendation: Implement a cleanup strategy (LRU cache, max size limit, or 2. Missing Delta ValidationLocation: The Recommendation: Add input validation for 3. Frame Cache API Not ExportedLocation: The frame cache module ( Recommendation: Export frame cache utilities from motion-dom. 4. Missing Error Handling for Concurrent RendersLocation:
Recommendation: Add guard against re-entrant calls. 🧪 Test CoverageGood Coverage
Missing Tests
📝 Style & ConventionsFollows CLAUDE.md guidelines well:
🎬 Recommendations SummaryMust Fix (Before Merge)
Should Fix (Important)
Nice to Have
Overall AssessmentQuality: ⭐⭐⭐⭐☆ (4/5) This is a solid implementation that addresses a real need. The architecture is clean and the code follows project conventions. However, the frame cache memory leak is a critical issue that must be addressed before merging, especially for the primary use case (Remotion video rendering with thousands of frames). Recommendation: Request changes to fix the memory leak, then approve with remaining items as follow-up improvements. Great work on this feature! 🎉 |
Pull Request Review: Manual Frame Rendering APISummaryThis PR adds support for manually advancing animations in environments without requestAnimationFrame (WebXR, Remotion, SSR video rendering). The implementation is well-structured and follows the codebase conventions outlined in CLAUDE.md. ✅ StrengthsArchitecture & Design
Code Quality
Test Coverage
🔍 Issues & Concerns1. Critical: Potential Race Condition in renderFrame()Location: packages/motion-dom/src/frameloop/render-frame.ts:65-75 Issue: If processFrame() throws an exception, useManualTiming won't be restored. This could leave the animation system in an inconsistent state. Recommendation: Use try-finally pattern to ensure useManualTiming is always restored. 2. Logic Inconsistency in JSAnimation.tick()Location: packages/motion-dom/src/animation/JSAnimation.ts:236-242 Issue: Why should a finished animation revert to "running" just because manual timing is enabled? This seems like a workaround for frame-by-frame scrubbing, but it breaks the state machine invariant and lacks explanation. Recommendation: Add a clear comment explaining this behavior, or consider alternative approaches. 3. Missing Teardown in finish()Location: packages/motion-dom/src/animation/JSAnimation.ts:468-476 Issue: In manual timing mode, animations never call teardown(), which means the activeAnimations.mainThread counter is never decremented and the driver is never stopped. This causes memory leaks in long-running Remotion/WebXR sessions. Recommendation: Either always teardown when finished, document that users must explicitly call .stop(), or add a cleanup API for manual timing mode. 4. Default FPS Value InconsistencyLocation: packages/motion-dom/src/frameloop/render-frame.ts:46-57 The default FPS is 30, but many contexts use different defaults (24fps, 30fps, 60fps). Recommendation: Consider making FPS required when using frame parameter, or document why 30 was chosen. 5. Type Safety: renderFrame({}) is ValidLocation: packages/motion-dom/src/frameloop/render-frame.ts:45 Calling renderFrame({}) is allowed but uses frameData.timestamp + delta, which might be unexpected. Recommendation: Consider making the options non-optional or use a discriminated union. 💡 Suggestions & Enhancements6. Performance: Redundant processFrame() Code DuplicationLocation: packages/motion-dom/src/frameloop/batcher.ts:95-113 The processFrame() function duplicates the entire frame processing loop from processBatch(). While noted as "unrolled for better per-frame performance", the duplication makes maintenance harder. 7. Missing Public API DocumentationThe PR body mentions setManualTiming(enabled), isManualTiming(), and useManualFrame() but they're not found in the code. Update the PR description to reflect what's actually included. 8. Demo App Could Be More DiscoverableLocation: dev/react/src/tests/manual-frame-control.tsx Great demo, but it's in tests/ which might not be intuitive. Consider moving to examples/. 9. Wake Condition LogicLocation: packages/motion-dom/src/frameloop/batcher.ts:82-87 The condition in wake() is subtle and hard to parse. Add an inline comment explaining the intended behavior. 🔒 Security ConsiderationsNo security concerns identified. ⚡ Performance ConsiderationsPositive:
Concerns:
📋 Checklist✅ Code follows CLAUDE.md style guidelines 🎯 VerdictConditional Approval - This is solid work that adds valuable functionality for Remotion/WebXR use cases. The core implementation is sound, but there are three issues that should be addressed before merging:
The other suggestions are nice-to-haves that can be addressed in follow-up PRs. Great work overall! The extensive test coverage is particularly impressive. 🚀 Fixes #2496 |
…ionFrame
This adds support for manually advancing animations in environments where
requestAnimationFrame is unavailable, such as WebXR immersive sessions,
Remotion video rendering, or server-side rendering of animations.
New APIs:
- renderFrame({ timestamp, frame, fps, delta }) - Manually render a frame
- setManualTiming(enabled) - Enable/disable manual timing mode globally
- isManualTiming() - Check if manual timing is enabled
- useManualFrame({ frame, fps }) - React hook for Remotion integration
Fixes #2496
https://claude.ai/code/session_01AFhy8F8ubRRHsau2GRdYAZ
- Add unit tests for useManualFrame hook demonstrating Remotion-style integration - Add tests for direct renderFrame usage with frame-by-frame stepping - Add tests for scrubbing backwards through animations - Add interactive dev demo with frame slider and step buttons https://claude.ai/code/session_01AFhy8F8ubRRHsau2GRdYAZ
- Create motion-remotion package with remotionDriver and useRemotionFrame hook - Add MotionGlobalConfig.driver for custom animation drivers - Disable WAAPI when custom driver or useManualTiming is active - Update batcher to skip rAF scheduling with custom driver - Export Driver type and frameloopDriver from motion-dom - Remove useManualFrame from framer-motion (moved to motion-remotion) - Add waapi supports tests for driver/timing checks Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove useManualTiming from MotionGlobalConfig - Remove setManualTiming and isManualTiming functions - Update batcher, waapi, and sync-time to only check for driver - Update all tests to use driver instead of useManualTiming - Use useLayoutEffect in useRemotionFrame for proper timing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users now wrap their composition with <MotionRemotion> instead of manually calling hooks. The component internally uses Remotion's useCurrentFrame/useVideoConfig and sets up the driver via useInsertionEffect. Also tightens comments across the branch. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cache the visual output (styles, CSS variables, SVG attributes) of every motion element per frame during first render. On revisit (scrubbing), apply cached styles instead of recomputing, enabling backward scrubbing in Remotion previews regardless of animation statefulness. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ustom driver The microtask batcher's wake() was incorrectly skipping queueMicrotask scheduling when a custom driver was set, preventing layout animation setup (projection system's didUpdate via microtask.read) from running in Remotion. Fix: allow non-keepAlive batchers to schedule regardless of driver. Tests mock getBoundingClientRect per-element (JSDOM returns zeros which the projection system discards) and flush microtasks after layout changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
814b27c to
114f505
Compare
Pull Request ReviewThis PR adds manual frame rendering support for environments without requestAnimationFrame (WebXR, Remotion, SSR). The implementation is well-designed and follows the repository conventions. ✅ Strengths1. Architecture & Design
2. API Design
3. Code Quality
4. Test Coverage
5. Integration Points
🔍 Observations & Suggestions1. State Management (Minor) // JSAnimation.ts:237-242
if (this.state === "finished" && this.holdTime === null) {
if (MotionGlobalConfig.useManualTiming && this.currentTime < totalDuration) {
this.state = "running"
} else {
this.currentTime = totalDuration
}
}This logic allows animations to "resurrect" from finished state in manual mode. While this makes sense for scrubbing backwards in video rendering, it could be worth documenting this behavior difference from normal mode. 2. Timestamp Calculation (Question) // render-frame.ts:59-62
} else {
frameDelta = delta !== undefined ? delta : 1000 / 60
frameTimestamp = frameData.timestamp + frameDelta
}When neither 3. Export Strategy
This means import { renderFrame } from "motion-dom"Consider whether this should also be exposed from the main 4. Potential Race Condition (Low Risk) // render-frame.ts:65-66
const previousManualTiming = MotionGlobalConfig.useManualTiming
MotionGlobalConfig.useManualTiming = true
// ... processing ...
MotionGlobalConfig.useManualTiming = previousManualTimingIf if (frameData.isProcessing) {
console.warn('renderFrame called during frame processing')
return
}5. Delta Calculation Consistency
This is correct but could be clearer. The frame-based path correctly uses fps for delta, but the timestamp path always assumes 60fps. Consider whether 6. File Size Consideration 🔒 Security & Performance
📋 Testing RecommendationsManual Testing Needed:
Additional Test Cases (Optional):
📚 Documentation Suggestions
🎯 Overall AssessmentThis is a high-quality implementation that solves a real problem for important use cases (Remotion, WebXR). The code is clean, well-tested, and follows repository conventions. The API design is intuitive and flexible. Recommendation: Approve with minor documentation improvements The concerns raised are minor and mostly about documentation clarity rather than implementation issues. The core implementation is solid and ready to merge. Great work! This will be a valuable addition for users working with video rendering and immersive environments. 🎬 Review by Claude Code |
This adds support for manually advancing animations in environments where
requestAnimationFrame is unavailable, such as WebXR immersive sessions,
Remotion video rendering, or server-side rendering of animations.
New APIs:
Fixes #2496
https://claude.ai/code/session_01AFhy8F8ubRRHsau2GRdYAZ