{"id":10917,"library":"framesync","title":"Framesync","description":"Framesync is a JavaScript library designed for scheduling functions into a synchronized render loop, primarily to prevent layout thrashing and ensure predictable execution order within a browser frame. It provides discrete steps for `read`, `update`, `preRender`, `render`, and `postRender` operations, allowing developers to organize DOM interactions efficiently. The current stable version is 6.1.2, and as part of the Popmotion ecosystem, it maintains a steady, mature release cadence focusing on stability and performance. Its primary differentiator is the explicit segregation of frame steps, which is crucial for high-performance animations and UI updates, notably used by libraries like Framer Motion to manage complex transform animations independently. Functions scheduled with Framesync receive frame data including `delta` (time since last frame) and `timestamp`.","status":"active","version":"6.1.2","language":"javascript","source_language":"en","source_url":"https://github.com/Popmotion/popmotion","tags":["javascript","animation","raf","typescript"],"install":[{"cmd":"npm install framesync","lang":"bash","label":"npm"},{"cmd":"yarn add framesync","lang":"bash","label":"yarn"},{"cmd":"pnpm add framesync","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Framesync uses an ESM default export for the main `sync` object. CommonJS `require` will result in accessing `sync.default` if supported by your build system, or an error in a pure ESM environment.","wrong":"const sync = require('framesync');","symbol":"sync","correct":"import sync from 'framesync';"},{"note":"Named exports like `cancelSync` are provided. CommonJS `require` for named exports will fail in pure ESM environments and may behave unexpectedly in others.","wrong":"const { cancelSync } = require('framesync');","symbol":"cancelSync","correct":"import { cancelSync } from 'framesync';"},{"note":"Use a type import for the `FrameData` interface (containing `delta` and `timestamp`) when working with TypeScript.","symbol":"FrameData","correct":"import type { FrameData } from 'framesync';"}],"quickstart":{"code":"import sync, { cancelSync } from 'framesync';\n\nlet animationProgress = 0;\nconst targetProgress = 100;\n\nconsole.log('Starting framesync animation...');\n\nconst updateFunction = ({ delta, timestamp }) => {\n  // In a real app, 'delta' would be used to calculate frame-rate independent updates.\n  // For this example, we'll just increment.\n  animationProgress += 1; \n\n  // Simulate some DOM read operation (e.g., getBoundingClientRect)\n  const elementWidth = document.body?.clientWidth || 0; \n  console.log(`[Frame ${timestamp.toFixed(2)}] Delta: ${delta.toFixed(2)}ms, Progress: ${animationProgress}, Width: ${elementWidth}`);\n\n  if (animationProgress >= targetProgress) {\n    cancelSync.update(updateFunction);\n    console.log('Animation complete!');\n  }\n};\n\nsync.update(updateFunction, true); // Schedule to run indefinitely on the update step\n\n// Simulate an immediate render call for some initial setup\nsync.render(() => {\n  // This would typically update DOM properties\n  // For example: document.body.style.transform = `translateX(${animationProgress}px)`;\n  console.log('Initial render step executed immediately.');\n}, false, true);\n","lang":"typescript","description":"Demonstrates scheduling a function to run on the `update` step of the render loop, accessing frame data, and canceling the process once a condition is met. It also shows an immediate render call."},"warnings":[{"fix":"Destructure the `FrameData` object immediately: `sync.update(({ delta, timestamp }) => { const currentDelta = delta; // use currentDelta asynchronously })`","message":"The `FrameData` object (containing `delta` and `timestamp`) passed to scheduled functions is recycled across frames for performance. If you need to use `delta` or `timestamp` asynchronously (e.g., in a `setTimeout` or `Promise`), you must destructure or copy its values, otherwise, they may change unexpectedly.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use `sync.step(callback, keepAlive, true)` to run on the current frame step. For example: `sync.update(() => console.log('now!'), false, true);`","message":"By default, `sync` functions schedule execution for the *next* time that frame step is fired. To execute a function on the *current* frame step, you must explicitly pass `true` as the third parameter for `immediate` execution.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always ensure there's a clear condition to call `cancelSync.step(yourProcessFunction)` when using `keepAlive: true`.","message":"When using the `keepAlive: true` option, a scheduled function will run indefinitely on every frame until it is explicitly cancelled using `cancelSync.<step>(process)`. Forgetting to cancel can lead to memory leaks and unnecessary CPU usage.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure you are using `import sync from 'framesync';` for the default export. If using CommonJS, try `const sync = require('framesync').default;` (though this is not recommended for pure ESM libraries).","cause":"Attempting to use CommonJS `require` or an incorrect import statement with a bundler that doesn't handle ESM default exports properly, leading to `sync` being an object with a `default` property, not the `sync` object itself.","error":"TypeError: framesync__WEBPACK_IMPORTED_MODULE_0__.default.update is not a function"},{"fix":"Ensure `cancelSync` is imported as a named export: `import { cancelSync } from 'framesync';`","cause":"`cancelSync` is a named export, and its methods (`.read`, `.update`, `.render`, etc.) are functions. This error often occurs if `cancelSync` itself is not correctly imported as a named export.","error":"Uncaught TypeError: cancelSync.render is not a function"}],"ecosystem":"npm"}