{"id":15387046,"url":"https://github.com/gkjohnson/js-framerate-optimizer","last_synced_at":"2025-11-13T22:52:51.990Z","repository":{"id":46941259,"uuid":"143386673","full_name":"gkjohnson/js-framerate-optimizer","owner":"gkjohnson","description":"Library for tracking and iteratively improving page framerate over time","archived":false,"fork":false,"pushed_at":"2023-10-22T08:45:19.000Z","size":1084,"stargazers_count":32,"open_issues_count":8,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-01T22:54:11.446Z","etag":null,"topics":["browser","fps","framerate","iterative","javascript","optimize","performance","process","quality","tweak","work"],"latest_commit_sha":null,"homepage":"https://gkjohnson.github.io/js-framerate-optimizer/example/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gkjohnson.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-08-03T06:23:12.000Z","updated_at":"2024-03-30T03:23:05.000Z","dependencies_parsed_at":"2023-02-05T07:01:02.887Z","dependency_job_id":"e7ef03e9-8365-4280-8906-e0bf8b9522d1","html_url":"https://github.com/gkjohnson/js-framerate-optimizer","commit_stats":{"total_commits":103,"total_committers":2,"mean_commits":51.5,"dds":"0.24271844660194175","last_synced_commit":"cac1c16b7f2434a45fb6089baafa4d782000eb3c"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkjohnson%2Fjs-framerate-optimizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkjohnson%2Fjs-framerate-optimizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkjohnson%2Fjs-framerate-optimizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkjohnson%2Fjs-framerate-optimizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gkjohnson","download_url":"https://codeload.github.com/gkjohnson/js-framerate-optimizer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219901349,"owners_count":16565956,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","fps","framerate","iterative","javascript","optimize","performance","process","quality","tweak","work"],"created_at":"2024-10-01T14:51:38.788Z","updated_at":"2025-11-13T22:52:46.954Z","avatar_url":"https://github.com/gkjohnson.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# js-framerate-optimizer\n\n[![npm version](https://img.shields.io/npm/v/framerate-optimizer.svg?style=flat-square)](https://www.npmjs.com/package/framerate-optimizer)\n[![build](https://img.shields.io/github/actions/workflow/status/gkjohnson/js-framerate-optimizer/node.js.yml?branch=master\u0026style=flat-square\u0026label=build)](https://github.com/gkjohnson/js-framerate-optimizer/actions)\n\nLibrary for tracking and iteratively improving framerate over time inspired by the [Babylon.SceneOptimizer](https://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer).\n\nThe terms \"increase work\" and \"decrease work\" are synonymous with \"improve quality\" and \"improve performance\" respectively.\n\n# Use\n\n```js\nimport { Optimizer } from '.../Optimizer.js';\n\n// wait for x milliseconds\nfunction wait(ms) {\n\n    const start = window.performance.now();\n    while (window.performance.now \u003c start + ms) {}\n\n}\n\n// optimize the work time until we reach the target framerate\nconst optimizer = new Optimizer();\noptimizer.addOptimization(delta =\u003e {\n\n    workTime += delta \u003c 0 ? -1 : 1;\n    return true;\n\n});\n\n// work loop\nlet workTime = 500;\n(function loop(){\n\n    optimizer.update();\n    wait(workTime);\n    requestAnimationFrame(loop);\n\n})();\n\n```\n\n# How it Works\n\nThe optimizer tracks the amount of time spent between frames or between calls to `begin` and `end` and calculates the difference between the target amount of time to spend and the actual time spent on the last frame. After the specified amount of time has passed the average time spent is calculated and the framerate the amount of work is either increased or decreased depending on whether or not the time spent was above or below the target. The amount of work is adjusted by iteratively calling prioritized optimizations and sampling framerate until the target work time is met.\n\n# API\n## Optimizer\n\n### .enabled\n\n```js\nenabled = true : Boolean\n```\n\nGetter and setter for enabling or disabling the optimizer. Elapsed time is reset on reenable.\n\n### .completed\n\n```js\ncompleted : Boolean\n```\n\nWhether or not the optimizer has stopped iterating and sampling the framerate.\n\n\n### .constructor\n\n```js\nconstructor( options : Object )\n```\n\nAll options can be accessed and modified on `Optimizer.options`.\n\n#### options.targetMillis\n\nThe target milliseconds to hit in the enclosed code block. This cannot be _less_ than `16.66...` because browser caps the framerate to 60 frames per second. If this is less than that the optimizer will continually decrease quality to try to get performance up.\n\nDefaults to `16.66...`.\n\n#### options.targetFramerate\n\nThe target framerate to hit. This overrides `targetMillis` if it is set.\n\nDefaults to `null`.\n\n#### options.interval\n\nHow often to perform a check sample the average framerate to try to optimize in milliseconds.\n\nDefaults to `500` or half a second.\n\n#### options.maxFrameSamples\n\nAt most how many frames can run before an optimization should occur. This is useful when code may not run consistently but runs as needed, meaning that checking after a fixed amount of time might mean that an inconsistent or no actual iterations has occurred. `Interval` should probably be set to `Infinity` in this case.\n\nDefaults to `Infinity`.\n\n#### options.waitMillis\n\nThe amount of time to wait between sampling frames for a new optimization. This is useful when an optimization may cause the framerate to drop for a frame or two -- such as with allocating a lot of new memory or new webgl render targets.\n\nDefaults to `0`;\n\n#### options.maxWaitFrames\n\nAt most how many frames to wait for.\n\nDefaults to `Infinity`;\n\n#### options.margin\n\nHow far outside of the target framerate must be in order for an optimization to occurs.\n\nDefaults to `0.05` or 5%.\n\n#### options.continuallyRefine\n\nBy default the optimizer will stop trying to optimize and optimization the page once the target framerate is hit or no more optimizations can run and will never try to improve quality of the page again after the first iteration.\n\nThis option allows the optimizer to ping pong between improving performance and quality continually to keep a steady framerate. Note that this may not be a good option when using \"expensive\" optimizations that may stall the frame for a moment, like compiling shaders.\n\nDefaults to `false`.\n\n#### options.increaseWork\n\nWhether the optimizer should ever try to increase the amount of work done at the cost of framerate. After the quality improvements are made the optimizer tries to improve the framerate until the target framerate is met.\n\nDefaults to `false`.\n\n### .dispose\n\n```js\ndispose() : void\n```\n\nRemoves window events that the optimizer listens for, including window `\"blur\"` and `\"focus\"`. It is expected that the optimizer is no longer used after this.\n\n### .addOptimization\n\n```js\naddOptimization( optimization : Optimization, priority = 0 : Number ) : void\n```\n\nTakes an instance of a `Optimization` (described below) and a priority by which to call the optimization. Optimizations are optimized iteratively until each priority level has been completely optimized then it will move to the next one. When improving quality the lowest priority level is started with to improve quality. The highest is started with when improving performance.\n\nExpensive but unnecessary work should be optimized at a high priority level. Critical functionality should be optimized at a low priority level.\n\n### .begin\n### .end\n\n```js\nbegin() : void\nend() : void\n```\n\n`begin` an `end` are used to encapsulate the code block to be optimized. Any optimizations being used should affect the performance of the code within that code block.\n\n```js\noptimizer.begin();\n\n// ... code to optimize ...\n\noptimizer.end();\n```\n\n### .update\n\n```js\nupdate() : void\n```\n\n`update` takes the place of both `begin()` and `end()` and should be called once per frame to optimize the full frame time.\n\n```js\n\nfunction loop() {\n\n    optimizer.update();\n\n    // ... code to optimize\n\n    requesAnimationFrame(loop);\n\n}\n```\n\n### .addSample\n\n```js\naddSample( time : Number ) : void\n```\n\nCall instead of `begin`, `end`, or `update` if you'd like to use a separate time-measuring mechanism that cannot be achieved with the aforementioned function, such as when measuring GPU work time with the [WebGL disjoint_timer_query](https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/).\n\n### .restart\n\n```js\nrestart() : void\n```\n\nRestarts optimization from the beginning.\n\nThis should be called if something on the page changed\nicantly which might give more room for improvement, such as significantly resizing the browser window with a WebGL app.\n\n## Optimization\n\nAn optimization base class for creating a reusable optimization to add to the `Optimizer`.\n\n### .optimize\n\n```js\noptimize( delta : Number, optimizer : Optimizer )\n```\n\nThe optimize function is called whenever an optimization should take place, either to improve performance or quality. The `delta` argument is the amount of milliseconds difference between the target framerate and the current framerate. A negative value means that less work should be done to hit the target.\n\nThe optimize function _must_ return `true` if the setting was optimized and 'false' if no optimization could occur, ie the setting being optimized could not be turned down any further or is at the lowest acceptable setting.\n\nThe second argument `optimizer` is the optimizer that is running the optimization.\n\n## SimpleOptimization\n\nA extension of `Optimization` that abstracts some of the basic functionality needed to implement it.\n\n### .canIncreaseWork / .canDecreaseWork\n\n```js\ncanIncreaseWork() : Boolean\ncanDecreaseWork() : Boolean\n```\n\nFunctions that should return true if the optimizer _can_ increase or decrease work. If they return true the associated optimization function will be called.\n\n### .increaseWork / .decreaseWork\n\n```js\nincreaesWork( delta : Number ) : void\ndecreaseWork( delta : Number ) : void\n```\n\nFunctions to increase or decrease work and optimize the frame if needed. These are called if the associated `canIncreaseWork` or `canDecreaseWork` return true.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgkjohnson%2Fjs-framerate-optimizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgkjohnson%2Fjs-framerate-optimizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgkjohnson%2Fjs-framerate-optimizer/lists"}