{"_id":"@pmndrs/scheduler","_rev":"8-894123eacd99990ef09a8cd6afbd156f","name":"@pmndrs/scheduler","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@pmndrs/scheduler","version":"0.1.0","keywords":["scheduler","frameloop","requestAnimationFrame","raf","game-loop","useFrame","react","pmndrs"],"author":{"url":"https://github.com/dennissmolek","name":"Dennis Smolek"},"license":"MIT","_id":"@pmndrs/scheduler@0.1.0","maintainers":[{"name":"abernier","email":"antoine.bernier@gmail.com"},{"name":"pmndrs01","email":"gnosissur@gmail.com"},{"name":"drcmda","email":"drcmda@gmail.com"},{"name":"bjornstar","email":"bjorn@bjornstar.com"},{"name":"dennissmolek","email":"dennis@smolek.dev"},{"name":"bela-bohlender","email":"bela@bohlender.email"},{"name":"isaacmason","email":"isaac@isaacmason.com"},{"name":"krispyaa","email":"kjbaumgartner@gmail.com"}],"homepage":"https://github.com/pmndrs/scheduler#readme","bugs":{"url":"https://github.com/pmndrs/scheduler/issues"},"dist":{"shasum":"29fffb91c71cbd968331cb00e6c9be3cb860ce92","tarball":"https://registry.npmjs.org/@pmndrs/scheduler/-/scheduler-0.1.0.tgz","fileCount":13,"integrity":"sha512-LjWt2FVi7RDOpgBdSBDxToQwnMWP1wkZwVeAkr8ARvVBtvlfyMqCCvr1y9YcLm9RTUhSebN5Bx4bJTntdSd22Q==","signatures":[{"sig":"MEUCIQDhgClVPGvl5dtrRrklHMdO+PpQdEyv4dW7FmNFCAQg6AIgNQ9c7/fcJXUVJp/8TZPdpkpoQAlhcHrgM4UjxCvNVVI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":166647},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.cjs"},"./package.json":"./package.json"},"gitHead":"e21c41da02fda3b32dcd8bda6d10d554e0a7c521","scripts":{"ci":"pnpm build && pnpm typecheck && pnpm lint && pnpm test && pnpm format","dev":"unbuild --stub","lint":"eslint src tests","stub":"unbuild --stub","test":"vitest run","build":"unbuild","format":"prettier --check .","prepack":"pnpm build","lint:fix":"eslint src tests --fix","typecheck":"tsc --noEmit","format:fix":"prettier --write .","test:watch":"vitest"},"_npmUser":{"name":"dennissmolek","email":"dennis@smolek.dev"},"repository":{"url":"git+https://github.com/pmndrs/scheduler.git","type":"git"},"_npmVersion":"10.9.7","description":"Framework-agnostic frame scheduler with phases, priorities and FPS throttling — the engine behind react-three-fiber's useFrame.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.2","devDependencies":{"jsdom":"^27.4.0","react":"^19.2.3","eslint":"^9.39.2","vitest":"^4.0.17","globals":"^16.4.0","unbuild":"^3.6.1","prettier":"^3.8.0","react-dom":"^19.2.3","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/node":"^22.0.0","@types/react":"^19.2.8","@types/react-dom":"^19.2.3","typescript-eslint":"^8.53.0","@vitest/coverage-v8":"^4.0.17","eslint-plugin-react":"^7.37.5","@testing-library/dom":"^10.4.1","eslint-plugin-vitest":"^0.5.4","@testing-library/react":"^16.3.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","eslint-plugin-react-hooks":"^5.2.0"},"peerDependencies":{"react":">=18","react-dom":">=18"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/scheduler_0.1.0_1782747358255_0.8442577245199305","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@pmndrs/scheduler","version":"0.2.0","keywords":["scheduler","frameloop","requestAnimationFrame","raf","game-loop","useFrame","react","pmndrs"],"author":{"url":"https://github.com/dennissmolek","name":"Dennis Smolek"},"license":"MIT","_id":"@pmndrs/scheduler@0.2.0","maintainers":[{"name":"abernier","email":"antoine.bernier@gmail.com"},{"name":"pmndrs01","email":"gnosissur@gmail.com"},{"name":"drcmda","email":"drcmda@gmail.com"},{"name":"bjornstar","email":"bjorn@bjornstar.com"},{"name":"dennissmolek","email":"dennis@smolek.dev"},{"name":"bela-bohlender","email":"bela@bohlender.email"},{"name":"isaacmason","email":"isaac@isaacmason.com"},{"name":"krispyaa","email":"kjbaumgartner@gmail.com"}],"homepage":"https://github.com/pmndrs/scheduler#readme","bugs":{"url":"https://github.com/pmndrs/scheduler/issues"},"dist":{"shasum":"378007e0f1c5897a08b74912a5f49470db3cc7b9","tarball":"https://registry.npmjs.org/@pmndrs/scheduler/-/scheduler-0.2.0.tgz","fileCount":13,"integrity":"sha512-Lv+4ZQjxw2BMcPDWHgcP2tULiEKZL+x5+mFW2YXWZUrDhT4h5PKpRv/U5ApweL+R319sdY63C688zd4QVamHvA==","signatures":[{"sig":"MEUCIQCSzhJWPgMMQUngectRurVjhxGpnmF5bvBZ1lpQlvlxOAIgZD17DM0+h1T/U6DcNB1BHCQJZI2wWymdqyUvW/P130Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@pmndrs%2fscheduler@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":246426},"main":"./dist/index.cjs","type":"module","_from":"file:/tmp/scheduler-package.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.cjs"},"./package.json":"./package.json"},"scripts":{"ci":"pnpm build && pnpm typecheck && pnpm lint && pnpm test && pnpm format","dev":"unbuild --stub","lint":"eslint src tests","stub":"unbuild --stub","test":"vitest run","build":"unbuild","format":"prettier --check .","lint:fix":"eslint src tests --fix","typecheck":"tsc --noEmit","format:fix":"prettier --write .","test:watch":"vitest","smoke:package":"node scripts/package-smoke.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:32297bfe-2701-4e53-97e9-45323033bb31"}},"_resolved":"/tmp/scheduler-package.tgz","_integrity":"sha512-Lv+4ZQjxw2BMcPDWHgcP2tULiEKZL+x5+mFW2YXWZUrDhT4h5PKpRv/U5ApweL+R319sdY63C688zd4QVamHvA==","repository":{"url":"git+https://github.com/pmndrs/scheduler.git","type":"git"},"_npmVersion":"11.5.1","description":"Framework-agnostic frame scheduler with phases, priorities and FPS throttling — the engine behind react-three-fiber's useFrame.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^27.4.0","react":"^19.2.3","eslint":"^9.39.2","vitest":"^4.0.17","globals":"^16.4.0","unbuild":"^3.6.1","prettier":"^3.8.0","react-dom":"^19.2.3","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/node":"^22.0.0","@types/react":"^19.2.8","@types/react-dom":"^19.2.3","typescript-eslint":"^8.53.0","@vitest/coverage-v8":"^4.0.17","eslint-plugin-react":"^7.37.5","@testing-library/dom":"^10.4.1","eslint-plugin-vitest":"^0.5.4","@testing-library/react":"^16.3.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","eslint-plugin-react-hooks":"^5.2.0"},"peerDependencies":{"react":">=18","react-dom":">=18"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/scheduler_0.2.0_1787564273959_0.5993134484177771","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@pmndrs/scheduler","version":"0.3.0","keywords":["scheduler","frameloop","requestAnimationFrame","raf","game-loop","useFrame","react","pmndrs"],"author":{"url":"https://github.com/dennissmolek","name":"Dennis Smolek"},"license":"MIT","_id":"@pmndrs/scheduler@0.3.0","maintainers":[{"name":"abernier","email":"antoine.bernier@gmail.com"},{"name":"drcmda","email":"drcmda@gmail.com"},{"name":"bjornstar","email":"bjorn@bjornstar.com"},{"name":"dennissmolek","email":"dennis@smolek.dev"},{"name":"bela-bohlender","email":"bela@bohlender.email"},{"name":"isaacmason","email":"isaac@isaacmason.com"},{"name":"krispyaa","email":"kjbaumgartner@gmail.com"}],"homepage":"https://github.com/pmndrs/scheduler#readme","bugs":{"url":"https://github.com/pmndrs/scheduler/issues"},"dist":{"shasum":"f38f4cfdb80f256ca73c1253972c5626679dd2b3","tarball":"https://registry.npmjs.org/@pmndrs/scheduler/-/scheduler-0.3.0.tgz","fileCount":13,"integrity":"sha512-zz1//QQphScVT8Hk/s9IIJBII8l0SIdN8DOKHChgE7BZfnJZiaZgXtpnhmRBVKsZeJBvMNvbGA/ALeqlIK3TbA==","signatures":[{"sig":"MEQCIHpffq0+BZoj12UvhL/5YRNiKsXWS29PcktEWTGXgPcfAiAY+pduv6Wru1dLNMcCaSqCQ28ivXPh0ko6QCZfyBPxHg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCzAT+wfeB8xkIooICQflpIedR2H/s8RMggZ3/hu4DGVAIgbT1Y07jr3RnqtVLP5t4ZQKbmmG5YjNQWmggire36qDM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@pmndrs%2fscheduler@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":299458},"main":"./dist/index.cjs","type":"module","_from":"file:/tmp/scheduler-package.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.cjs"},"./package.json":"./package.json"},"scripts":{"ci":"pnpm build && pnpm typecheck && pnpm lint && pnpm test && pnpm format","dev":"unbuild --stub","lint":"eslint src tests","stub":"unbuild --stub","test":"vitest run","build":"unbuild","format":"prettier --check .","lint:fix":"eslint src tests --fix","typecheck":"tsc --noEmit","format:fix":"prettier --write .","test:watch":"vitest","smoke:package":"node scripts/package-smoke.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"32297bfe-2701-4e53-97e9-45323033bb31"}},"_resolved":"/tmp/scheduler-package.tgz","_integrity":"sha512-zz1//QQphScVT8Hk/s9IIJBII8l0SIdN8DOKHChgE7BZfnJZiaZgXtpnhmRBVKsZeJBvMNvbGA/ALeqlIK3TbA==","repository":{"url":"git+https://github.com/pmndrs/scheduler.git","type":"git"},"_npmVersion":"11.5.1","description":"Framework-agnostic frame scheduler with phases, priorities and FPS throttling — the engine behind react-three-fiber's useFrame.","directories":{},"sideEffects":false,"_nodeVersion":"24.21.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^27.4.0","react":"^19.2.3","eslint":"^9.39.2","vitest":"^4.0.17","globals":"^16.4.0","unbuild":"^3.6.1","prettier":"^3.8.0","react-dom":"^19.2.3","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/node":"^22.0.0","@types/react":"^19.2.8","@types/react-dom":"^19.2.3","typescript-eslint":"^8.53.0","@vitest/coverage-v8":"^4.0.17","eslint-plugin-react":"^7.37.5","@testing-library/dom":"^10.4.1","eslint-plugin-vitest":"^0.5.4","@testing-library/react":"^16.3.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","eslint-plugin-react-hooks":"^5.2.0"},"peerDependencies":{"react":">=18","react-dom":">=18"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/scheduler_0.3.0_1791170719172_0.16310079971862268","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-06-29T15:35:58.093Z","modified":"2026-10-16T14:39:59.481Z","0.1.0":"2026-06-29T15:35:58.416Z","0.2.0":"2026-08-24T09:37:54.102Z","0.3.0":"2026-10-05T03:25:19.254Z"},"bugs":{"url":"https://github.com/pmndrs/scheduler/issues"},"author":{"url":"https://github.com/dennissmolek","name":"Dennis Smolek"},"license":"MIT","homepage":"https://github.com/pmndrs/scheduler#readme","keywords":["scheduler","frameloop","requestAnimationFrame","raf","game-loop","useFrame","react","pmndrs"],"repository":{"url":"git+https://github.com/pmndrs/scheduler.git","type":"git"},"description":"Framework-agnostic frame scheduler with phases, priorities and FPS throttling — the engine behind react-three-fiber's useFrame.","maintainers":[{"email":"dennis@smolek.dev","name":"dennissmolek"},{"email":"kjbaumgartner@gmail.com","name":"krispyaa"}],"readme":"# @pmndrs/scheduler\n\nA small, **standalone**, framework-agnostic frame scheduler with **phases**, **priorities**, and **per-job FPS throttling**. One RAF loop, any renderer, no framework required.\n\n- **One RAF loop** for your whole app, with independent lifecycle modes per root\n- **Cross-root ordering** with stable `order` preferences and `before`/`after` dependencies\n- **Phases** (`start → input → physics → update → render → finish`) you can extend at runtime\n- **Priorities** and cross-job `before`/`after` ordering (topological sort)\n- **FPS throttling** per job, and a **fixed-timestep** `physics` phase (1/60) with `overstep` for interpolation\n- **Demand** (`invalidate`) and **manual** (`step`) frame modes\n- Zero dependencies. Vanilla core pulls in **no React**.\n\n## Status: standalone, port in progress\n\nThis is its own package, not a build artifact of another library. It began as the core\nframe scheduler inside [react-three-fiber](https://github.com/pmndrs/react-three-fiber)\n(the engine behind its `useFrame`) and is being **ported into an independent, framework-agnostic\nlibrary** with its own API, docs, tests, and release cycle. The r3f lineage is where it came\nfrom — not something it depends on; the vanilla core ships zero dependencies and no React.\n\n> Pre-1.0: the port is ongoing and the API is still settling, but the package is standalone\n> and usable today. Expect refinements before 1.0.\n\n## Install\n\n```bash\nnpm install @pmndrs/scheduler\n```\n\nReact is an optional peer dependency, only needed for the `/react` entry.\n\n## Vanilla\n\n```ts\nimport { getScheduler } from '@pmndrs/scheduler'\n\nconst scheduler = getScheduler()\n\nscheduler.register(\n  (state, delta) => {\n    // called every frame: state = { time, delta, elapsed, frame }\n  },\n  { phase: 'update' },\n)\n```\n\nNo host renderer or setup flag is required — registering a job lazily creates the\nscheduler's root and starts the loop. If a host (e.g. a `<Canvas>`) registers later, it\nadopts jobs already registered.\n\nMulti-root hosts still share one RAF driver, but each root can independently use `always`,\n`demand`, or `never`. Use `setRootFrameloop` and `invalidateRoot` when one canvas should\nsleep or wake without affecting its siblings.\n\n## React\n\n```tsx\nimport { useFrame } from '@pmndrs/scheduler/react'\n\nfunction Spinner() {\n  useFrame((state, delta) => {\n    // runs every frame\n  })\n  return null\n}\n```\n\n`useFrame` returns a controls object (`{ id, scheduler, step, stepAll, pause, resume, isPaused }`)\nwhere `isPaused` is reactive.\n\n## Entry points\n\n| Import                    | Contents                                   |\n| ------------------------- | ------------------------------------------ |\n| `@pmndrs/scheduler`       | `Scheduler`, `getScheduler`, all types     |\n| `@pmndrs/scheduler/react` | `useFrame` + re-exported scheduler + types |\n\n## Core ideas\n\nEvery `register` / `useFrame` call creates a **job**. Jobs run in named **phases**\n(`start → input → physics → update → render → finish`) that you can extend at runtime, with\n**priorities** and `before`/`after` dependencies inside each phase. It's a DAG scheduler:\nyou declare ordering, it figures out the sequence — no priority-number guessing.\n\n```ts\nscheduler.addPhase('ai', { after: 'physics', before: 'update' })\n\nscheduler.register(processInput, { phase: 'input' })\nscheduler.register((state, dt) => world.step(dt), { phase: 'physics' }) // dt is a fixed 1/60\nscheduler.register(updateAI, { phase: 'ai', fps: 20 })\nscheduler.register(render, { phase: 'render' })\n```\n\n## Documentation\n\nThree guides, roughly in reading order. **New here? Start with Concepts** — it explains the\nmental model (jobs, phases, the frame budget) that the API references build on.\n\n- **[Concepts](./docs/concepts.md)** — start here. Jobs, phases, the frame budget, FPS throttling, frameloop modes, and the design rationale (why named phases beat priority numbers), ending in a full game-loop example.\n- **[useFrame Hook](./docs/use-frame.md)** — the React API: registration timing, options, controls, examples, and best practices.\n- **[Scheduler API](./docs/scheduler.md)** — the full vanilla surface: roots, phases, job registration & control, frameloop, demand mode, manual stepping, and testing.\n\n## Examples\n\nRunnable demos live in [`examples/`](./examples) — a [vanilla](./examples/vanilla) app and a\n[React](./examples/react) app. From either directory: `pnpm install && pnpm dev`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}