@armniko/ticker
Advanced tools
+217
-1
@@ -1,1 +0,217 @@ | ||
| var s=class{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(s){this.collectFps(s),this._msSinceLastCalculation+=s.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(s){this._lowFpsCallback=s}setMinFps(s){return this._minFps=s,this}collectFps(s){this._lastChecks.push(Math.round(1e3/s.deltaMs))}calculateAverageFps(){const s=this._lastChecks.reduce((s,e)=>s+e,0);this._currentFps=Math.round(s/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}},e=class{_fps=new s;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(s){this.setFps({min:s?.minFps||0,max:s?.maxFps||60,expected:s?.expectedFps||60}),s?.onDrawTick&&this.addDrawTask(s.onDrawTick),s?.onLogicTick&&this.addLogicTask(s.onLogicTick),s?.onLowFps&&this.addLowFpsTask(s.onLowFps),this._fps.onLowFps(()=>{this._lowFpsQueue.forEach(s=>s.callback(this.fps()))})}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(s){return s.min&&s.min>0&&this._fps.setMinFps(s.min),s.max&&s.max>0&&(this._maxFps=this.compensatedMaxFps(s.max)),s.expected&&s.expected>0&&(this._expectedFps=s.expected),this}addDrawTask(s){return{index:this._drawQueue.push({callback:s})-1,type:"draw"}}addLogicTask(s){return{index:this._logicQueue.push({callback:s})-1,type:"logic"}}addLowFpsTask(s){return{index:this._lowFpsQueue.push({callback:s})-1,type:"low-fps"}}remove(s){switch(s.type){case"draw":this._drawQueue.splice(s.index,1);break;case"logic":this._logicQueue.splice(s.index,1);break;case"low-fps":this._lowFpsQueue.splice(s.index,1)}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(s){const e=1e3/this._maxFps,t=s-this._lastTimestamp;t>=e&&(this._time={delta:t/1e3,deltaMs:t},this._lastTimestamp=s,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const s=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const e={delta:s/1e3,deltaMs:s};for(;this._logicTicksAccumulatedMs>=s;)this._logicQueue.forEach(s=>s.callback(e)),this._logicTicksAccumulatedMs-=s}runDrawQueue(){this._drawQueue.forEach(s=>s.callback(this._time))}compensatedMaxFps(s){return Math.floor(1.1*s)+10*Math.floor(s/100)}},t=class extends e{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(s=void 0){this._logicQueue.forEach(e=>e.callback(s||{delta:1/this.fps(),deltaMs:1e3/this.fps()}))}simulateDrawTick(s=void 0){this._drawQueue.forEach(e=>e.callback(s||{delta:1/this.fps(),deltaMs:1e3/this.fps()}))}simulateLowFps(){this._lowFpsQueue.forEach(s=>s.callback(this.fps()))}};export{e as Ticker,t as TickerMock}; | ||
| //#region src/fps/fps.ts | ||
| var Fps = class { | ||
| _minFps; | ||
| _currentFps = 60; | ||
| _lastChecks = []; | ||
| _calculateFpsEachMs = 2e3; | ||
| _msSinceLastCalculation = 0; | ||
| _lowFpsInRow = 0; | ||
| _lowFpsCallback; | ||
| currentFps() { | ||
| return this._currentFps; | ||
| } | ||
| calculate(time) { | ||
| this.collectFps(time); | ||
| this._msSinceLastCalculation += time.deltaMs; | ||
| if (this._msSinceLastCalculation >= this._calculateFpsEachMs) { | ||
| this._msSinceLastCalculation = 0; | ||
| this.calculateAverageFps(); | ||
| this.checkAndNotifyLowFps(); | ||
| } | ||
| } | ||
| onLowFps(callback) { | ||
| this._lowFpsCallback = callback; | ||
| } | ||
| setMinFps(minFps) { | ||
| this._minFps = minFps; | ||
| return this; | ||
| } | ||
| collectFps(time) { | ||
| this._lastChecks.push(Math.round(1e3 / time.deltaMs)); | ||
| } | ||
| calculateAverageFps() { | ||
| const sumFps = this._lastChecks.reduce((a, b) => a + b, 0); | ||
| this._currentFps = Math.round(sumFps / this._lastChecks.length); | ||
| this._lastChecks = []; | ||
| } | ||
| checkAndNotifyLowFps() { | ||
| if (this._minFps && this._currentFps < this._minFps) { | ||
| this._lowFpsInRow++; | ||
| if (this._lowFpsInRow === 5) { | ||
| this._lowFpsInRow = 0; | ||
| if (this._lowFpsCallback) this._lowFpsCallback(); | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/ticker/ticker.ts | ||
| var Ticker = class { | ||
| _fps = new Fps(); | ||
| _drawQueue = []; | ||
| _logicQueue = []; | ||
| _lowFpsQueue = []; | ||
| _maxFps; | ||
| _expectedFps; | ||
| _time = { | ||
| delta: 0, | ||
| deltaMs: 0 | ||
| }; | ||
| _lastTimestamp = 0; | ||
| _logicTicksAccumulatedMs = 0; | ||
| _requestFrameId; | ||
| constructor(options) { | ||
| this.setFps({ | ||
| min: options?.minFps || 0, | ||
| max: options?.maxFps || 60, | ||
| expected: options?.expectedFps || 60 | ||
| }); | ||
| if (options?.onDrawTick) this.addDrawTask(options.onDrawTick); | ||
| if (options?.onLogicTick) this.addLogicTask(options.onLogicTick); | ||
| if (options?.onLowFps) this.addLowFpsTask(options.onLowFps); | ||
| this._fps.onLowFps(() => { | ||
| this._lowFpsQueue.forEach((item) => item.callback(this.fps())); | ||
| }); | ||
| } | ||
| start() { | ||
| this._lastTimestamp = performance.now(); | ||
| this.loop(this._lastTimestamp); | ||
| } | ||
| stop() { | ||
| if (this._requestFrameId) { | ||
| window.cancelAnimationFrame(this._requestFrameId); | ||
| this._requestFrameId = void 0; | ||
| } | ||
| } | ||
| isStarted() { | ||
| return !!this._requestFrameId; | ||
| } | ||
| setFps(options) { | ||
| if (options.min && options.min > 0) this._fps.setMinFps(options.min); | ||
| if (options.max && options.max > 0) this._maxFps = this.compensatedMaxFps(options.max); | ||
| if (options.expected && options.expected > 0) this._expectedFps = options.expected; | ||
| return this; | ||
| } | ||
| addDrawTask(callback) { | ||
| return { | ||
| index: this._drawQueue.push({ callback }) - 1, | ||
| type: "draw" | ||
| }; | ||
| } | ||
| addLogicTask(callback) { | ||
| return { | ||
| index: this._logicQueue.push({ callback }) - 1, | ||
| type: "logic" | ||
| }; | ||
| } | ||
| addLowFpsTask(callback) { | ||
| return { | ||
| index: this._lowFpsQueue.push({ callback }) - 1, | ||
| type: "low-fps" | ||
| }; | ||
| } | ||
| remove(taskId) { | ||
| switch (taskId.type) { | ||
| case "draw": | ||
| this._drawQueue.splice(taskId.index, 1); | ||
| break; | ||
| case "logic": | ||
| this._logicQueue.splice(taskId.index, 1); | ||
| break; | ||
| case "low-fps": | ||
| this._lowFpsQueue.splice(taskId.index, 1); | ||
| break; | ||
| } | ||
| } | ||
| fps() { | ||
| return this._fps.currentFps(); | ||
| } | ||
| /** | ||
| * @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead. | ||
| */ | ||
| msBetweenTicks() { | ||
| return this._time.deltaMs; | ||
| } | ||
| /** | ||
| * @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead. | ||
| */ | ||
| ticksMissed() { | ||
| return this._time.deltaMs / (1e3 / this._expectedFps); | ||
| } | ||
| loop(currentTimestamp) { | ||
| const maxDeltaMs = 1e3 / this._maxFps; | ||
| const deltaMs = currentTimestamp - this._lastTimestamp; | ||
| if (deltaMs >= maxDeltaMs) { | ||
| this._time = { | ||
| delta: deltaMs / 1e3, | ||
| deltaMs | ||
| }; | ||
| this._lastTimestamp = currentTimestamp; | ||
| this._fps.calculate(this._time); | ||
| this.runQueue(); | ||
| } | ||
| this._requestFrameId = window.requestAnimationFrame(this.loop.bind(this)); | ||
| } | ||
| runQueue() { | ||
| if (this._logicQueue.length > 0) this.runLogicQueue(); | ||
| if (this._drawQueue.length > 0) this.runDrawQueue(); | ||
| } | ||
| runLogicQueue() { | ||
| const expectedDeltaMs = 1e3 / this._expectedFps; | ||
| this._logicTicksAccumulatedMs += this._time.deltaMs; | ||
| const time = { | ||
| delta: expectedDeltaMs / 1e3, | ||
| deltaMs: expectedDeltaMs | ||
| }; | ||
| while (this._logicTicksAccumulatedMs >= expectedDeltaMs) { | ||
| this._logicQueue.forEach((item) => item.callback(time)); | ||
| this._logicTicksAccumulatedMs -= expectedDeltaMs; | ||
| } | ||
| } | ||
| runDrawQueue() { | ||
| this._drawQueue.forEach((item) => item.callback(this._time)); | ||
| } | ||
| compensatedMaxFps(maxFps) { | ||
| return Math.floor(maxFps * 1.1) + Math.floor(maxFps / 100) * 10; | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/ticker/ticker-mock.ts | ||
| var TickerMock = class extends Ticker { | ||
| _isStarted = false; | ||
| start() { | ||
| this._isStarted = true; | ||
| } | ||
| stop() { | ||
| this._isStarted = false; | ||
| } | ||
| isStarted() { | ||
| return this._isStarted; | ||
| } | ||
| fps() { | ||
| return 60; | ||
| } | ||
| msBetweenTicks() { | ||
| return 1e3 / 60; | ||
| } | ||
| ticksMissed() { | ||
| return 1; | ||
| } | ||
| simulateLogicTick(time = void 0) { | ||
| this._logicQueue.forEach((item) => item.callback(time || { | ||
| delta: 1 / this.fps(), | ||
| deltaMs: 1e3 / this.fps() | ||
| })); | ||
| } | ||
| simulateDrawTick(time = void 0) { | ||
| this._drawQueue.forEach((item) => item.callback(time || { | ||
| delta: 1 / this.fps(), | ||
| deltaMs: 1e3 / this.fps() | ||
| })); | ||
| } | ||
| simulateLowFps() { | ||
| this._lowFpsQueue.forEach((item) => item.callback(this.fps())); | ||
| } | ||
| }; | ||
| //#endregion | ||
| export { Ticker, TickerMock }; |
+223
-1
@@ -1,1 +0,223 @@ | ||
| !function(s,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((s="undefined"!=typeof globalThis?globalThis:s||self).Ticker={})}(this,function(s){Object.defineProperty(s,Symbol.toStringTag,{value:"Module"});var e=class{_minFps;_currentFps=60;_lastChecks=[];_calculateFpsEachMs=2e3;_msSinceLastCalculation=0;_lowFpsInRow=0;_lowFpsCallback;currentFps(){return this._currentFps}calculate(s){this.collectFps(s),this._msSinceLastCalculation+=s.deltaMs,this._msSinceLastCalculation>=this._calculateFpsEachMs&&(this._msSinceLastCalculation=0,this.calculateAverageFps(),this.checkAndNotifyLowFps())}onLowFps(s){this._lowFpsCallback=s}setMinFps(s){return this._minFps=s,this}collectFps(s){this._lastChecks.push(Math.round(1e3/s.deltaMs))}calculateAverageFps(){const s=this._lastChecks.reduce((s,e)=>s+e,0);this._currentFps=Math.round(s/this._lastChecks.length),this._lastChecks=[]}checkAndNotifyLowFps(){this._minFps&&this._currentFps<this._minFps&&(this._lowFpsInRow++,5===this._lowFpsInRow&&(this._lowFpsInRow=0,this._lowFpsCallback&&this._lowFpsCallback()))}},t=class{_fps=new e;_drawQueue=[];_logicQueue=[];_lowFpsQueue=[];_maxFps;_expectedFps;_time={delta:0,deltaMs:0};_lastTimestamp=0;_logicTicksAccumulatedMs=0;_requestFrameId;constructor(s){this.setFps({min:s?.minFps||0,max:s?.maxFps||60,expected:s?.expectedFps||60}),s?.onDrawTick&&this.addDrawTask(s.onDrawTick),s?.onLogicTick&&this.addLogicTask(s.onLogicTick),s?.onLowFps&&this.addLowFpsTask(s.onLowFps),this._fps.onLowFps(()=>{this._lowFpsQueue.forEach(s=>s.callback(this.fps()))})}start(){this._lastTimestamp=performance.now(),this.loop(this._lastTimestamp)}stop(){this._requestFrameId&&(window.cancelAnimationFrame(this._requestFrameId),this._requestFrameId=void 0)}isStarted(){return!!this._requestFrameId}setFps(s){return s.min&&s.min>0&&this._fps.setMinFps(s.min),s.max&&s.max>0&&(this._maxFps=this.compensatedMaxFps(s.max)),s.expected&&s.expected>0&&(this._expectedFps=s.expected),this}addDrawTask(s){return{index:this._drawQueue.push({callback:s})-1,type:"draw"}}addLogicTask(s){return{index:this._logicQueue.push({callback:s})-1,type:"logic"}}addLowFpsTask(s){return{index:this._lowFpsQueue.push({callback:s})-1,type:"low-fps"}}remove(s){switch(s.type){case"draw":this._drawQueue.splice(s.index,1);break;case"logic":this._logicQueue.splice(s.index,1);break;case"low-fps":this._lowFpsQueue.splice(s.index,1)}}fps(){return this._fps.currentFps()}msBetweenTicks(){return this._time.deltaMs}ticksMissed(){return this._time.deltaMs/(1e3/this._expectedFps)}loop(s){const e=1e3/this._maxFps,t=s-this._lastTimestamp;t>=e&&(this._time={delta:t/1e3,deltaMs:t},this._lastTimestamp=s,this._fps.calculate(this._time),this.runQueue()),this._requestFrameId=window.requestAnimationFrame(this.loop.bind(this))}runQueue(){this._logicQueue.length>0&&this.runLogicQueue(),this._drawQueue.length>0&&this.runDrawQueue()}runLogicQueue(){const s=1e3/this._expectedFps;this._logicTicksAccumulatedMs+=this._time.deltaMs;const e={delta:s/1e3,deltaMs:s};for(;this._logicTicksAccumulatedMs>=s;)this._logicQueue.forEach(s=>s.callback(e)),this._logicTicksAccumulatedMs-=s}runDrawQueue(){this._drawQueue.forEach(s=>s.callback(this._time))}compensatedMaxFps(s){return Math.floor(1.1*s)+10*Math.floor(s/100)}};s.Ticker=t,s.TickerMock=class extends t{_isStarted=!1;start(){this._isStarted=!0}stop(){this._isStarted=!1}isStarted(){return this._isStarted}fps(){return 60}msBetweenTicks(){return 1e3/60}ticksMissed(){return 1}simulateLogicTick(s=void 0){this._logicQueue.forEach(e=>e.callback(s||{delta:1/this.fps(),deltaMs:1e3/this.fps()}))}simulateDrawTick(s=void 0){this._drawQueue.forEach(e=>e.callback(s||{delta:1/this.fps(),deltaMs:1e3/this.fps()}))}simulateLowFps(){this._lowFpsQueue.forEach(s=>s.callback(this.fps()))}}}); | ||
| (function(global, factory) { | ||
| typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.Ticker = {})); | ||
| })(this, function(exports) { | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| //#region src/fps/fps.ts | ||
| var Fps = class { | ||
| _minFps; | ||
| _currentFps = 60; | ||
| _lastChecks = []; | ||
| _calculateFpsEachMs = 2e3; | ||
| _msSinceLastCalculation = 0; | ||
| _lowFpsInRow = 0; | ||
| _lowFpsCallback; | ||
| currentFps() { | ||
| return this._currentFps; | ||
| } | ||
| calculate(time) { | ||
| this.collectFps(time); | ||
| this._msSinceLastCalculation += time.deltaMs; | ||
| if (this._msSinceLastCalculation >= this._calculateFpsEachMs) { | ||
| this._msSinceLastCalculation = 0; | ||
| this.calculateAverageFps(); | ||
| this.checkAndNotifyLowFps(); | ||
| } | ||
| } | ||
| onLowFps(callback) { | ||
| this._lowFpsCallback = callback; | ||
| } | ||
| setMinFps(minFps) { | ||
| this._minFps = minFps; | ||
| return this; | ||
| } | ||
| collectFps(time) { | ||
| this._lastChecks.push(Math.round(1e3 / time.deltaMs)); | ||
| } | ||
| calculateAverageFps() { | ||
| const sumFps = this._lastChecks.reduce((a, b) => a + b, 0); | ||
| this._currentFps = Math.round(sumFps / this._lastChecks.length); | ||
| this._lastChecks = []; | ||
| } | ||
| checkAndNotifyLowFps() { | ||
| if (this._minFps && this._currentFps < this._minFps) { | ||
| this._lowFpsInRow++; | ||
| if (this._lowFpsInRow === 5) { | ||
| this._lowFpsInRow = 0; | ||
| if (this._lowFpsCallback) this._lowFpsCallback(); | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/ticker/ticker.ts | ||
| var Ticker = class { | ||
| _fps = new Fps(); | ||
| _drawQueue = []; | ||
| _logicQueue = []; | ||
| _lowFpsQueue = []; | ||
| _maxFps; | ||
| _expectedFps; | ||
| _time = { | ||
| delta: 0, | ||
| deltaMs: 0 | ||
| }; | ||
| _lastTimestamp = 0; | ||
| _logicTicksAccumulatedMs = 0; | ||
| _requestFrameId; | ||
| constructor(options) { | ||
| this.setFps({ | ||
| min: options?.minFps || 0, | ||
| max: options?.maxFps || 60, | ||
| expected: options?.expectedFps || 60 | ||
| }); | ||
| if (options?.onDrawTick) this.addDrawTask(options.onDrawTick); | ||
| if (options?.onLogicTick) this.addLogicTask(options.onLogicTick); | ||
| if (options?.onLowFps) this.addLowFpsTask(options.onLowFps); | ||
| this._fps.onLowFps(() => { | ||
| this._lowFpsQueue.forEach((item) => item.callback(this.fps())); | ||
| }); | ||
| } | ||
| start() { | ||
| this._lastTimestamp = performance.now(); | ||
| this.loop(this._lastTimestamp); | ||
| } | ||
| stop() { | ||
| if (this._requestFrameId) { | ||
| window.cancelAnimationFrame(this._requestFrameId); | ||
| this._requestFrameId = void 0; | ||
| } | ||
| } | ||
| isStarted() { | ||
| return !!this._requestFrameId; | ||
| } | ||
| setFps(options) { | ||
| if (options.min && options.min > 0) this._fps.setMinFps(options.min); | ||
| if (options.max && options.max > 0) this._maxFps = this.compensatedMaxFps(options.max); | ||
| if (options.expected && options.expected > 0) this._expectedFps = options.expected; | ||
| return this; | ||
| } | ||
| addDrawTask(callback) { | ||
| return { | ||
| index: this._drawQueue.push({ callback }) - 1, | ||
| type: "draw" | ||
| }; | ||
| } | ||
| addLogicTask(callback) { | ||
| return { | ||
| index: this._logicQueue.push({ callback }) - 1, | ||
| type: "logic" | ||
| }; | ||
| } | ||
| addLowFpsTask(callback) { | ||
| return { | ||
| index: this._lowFpsQueue.push({ callback }) - 1, | ||
| type: "low-fps" | ||
| }; | ||
| } | ||
| remove(taskId) { | ||
| switch (taskId.type) { | ||
| case "draw": | ||
| this._drawQueue.splice(taskId.index, 1); | ||
| break; | ||
| case "logic": | ||
| this._logicQueue.splice(taskId.index, 1); | ||
| break; | ||
| case "low-fps": | ||
| this._lowFpsQueue.splice(taskId.index, 1); | ||
| break; | ||
| } | ||
| } | ||
| fps() { | ||
| return this._fps.currentFps(); | ||
| } | ||
| /** | ||
| * @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead. | ||
| */ | ||
| msBetweenTicks() { | ||
| return this._time.deltaMs; | ||
| } | ||
| /** | ||
| * @deprecated Use `time.deltaMs` provided in draw/logic task callbacks instead. | ||
| */ | ||
| ticksMissed() { | ||
| return this._time.deltaMs / (1e3 / this._expectedFps); | ||
| } | ||
| loop(currentTimestamp) { | ||
| const maxDeltaMs = 1e3 / this._maxFps; | ||
| const deltaMs = currentTimestamp - this._lastTimestamp; | ||
| if (deltaMs >= maxDeltaMs) { | ||
| this._time = { | ||
| delta: deltaMs / 1e3, | ||
| deltaMs | ||
| }; | ||
| this._lastTimestamp = currentTimestamp; | ||
| this._fps.calculate(this._time); | ||
| this.runQueue(); | ||
| } | ||
| this._requestFrameId = window.requestAnimationFrame(this.loop.bind(this)); | ||
| } | ||
| runQueue() { | ||
| if (this._logicQueue.length > 0) this.runLogicQueue(); | ||
| if (this._drawQueue.length > 0) this.runDrawQueue(); | ||
| } | ||
| runLogicQueue() { | ||
| const expectedDeltaMs = 1e3 / this._expectedFps; | ||
| this._logicTicksAccumulatedMs += this._time.deltaMs; | ||
| const time = { | ||
| delta: expectedDeltaMs / 1e3, | ||
| deltaMs: expectedDeltaMs | ||
| }; | ||
| while (this._logicTicksAccumulatedMs >= expectedDeltaMs) { | ||
| this._logicQueue.forEach((item) => item.callback(time)); | ||
| this._logicTicksAccumulatedMs -= expectedDeltaMs; | ||
| } | ||
| } | ||
| runDrawQueue() { | ||
| this._drawQueue.forEach((item) => item.callback(this._time)); | ||
| } | ||
| compensatedMaxFps(maxFps) { | ||
| return Math.floor(maxFps * 1.1) + Math.floor(maxFps / 100) * 10; | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region src/ticker/ticker-mock.ts | ||
| var TickerMock = class extends Ticker { | ||
| _isStarted = false; | ||
| start() { | ||
| this._isStarted = true; | ||
| } | ||
| stop() { | ||
| this._isStarted = false; | ||
| } | ||
| isStarted() { | ||
| return this._isStarted; | ||
| } | ||
| fps() { | ||
| return 60; | ||
| } | ||
| msBetweenTicks() { | ||
| return 1e3 / 60; | ||
| } | ||
| ticksMissed() { | ||
| return 1; | ||
| } | ||
| simulateLogicTick(time = void 0) { | ||
| this._logicQueue.forEach((item) => item.callback(time || { | ||
| delta: 1 / this.fps(), | ||
| deltaMs: 1e3 / this.fps() | ||
| })); | ||
| } | ||
| simulateDrawTick(time = void 0) { | ||
| this._drawQueue.forEach((item) => item.callback(time || { | ||
| delta: 1 / this.fps(), | ||
| deltaMs: 1e3 / this.fps() | ||
| })); | ||
| } | ||
| simulateLowFps() { | ||
| this._lowFpsQueue.forEach((item) => item.callback(this.fps())); | ||
| } | ||
| }; | ||
| //#endregion | ||
| exports.Ticker = Ticker; | ||
| exports.TickerMock = TickerMock; | ||
| }); |
+30
-11
| { | ||
| "name": "@armniko/ticker", | ||
| "version": "2.1.1", | ||
| "description": "Javascript/typescript library for running app loop with separate logical/drawing ticks and FPS limitation.", | ||
| "version": "2.2.0", | ||
| "description": "A lightweight, zero-dependency JavaScript/TypeScript library for running an application loop with separate logic and draw ticks, FPS limiting, and low-FPS detection.", | ||
| "author": "ArmΔ«ns Nikolajevs <armins.nikolajevs@gmail.com>", | ||
@@ -12,10 +12,30 @@ "license": "MIT", | ||
| "ticker", | ||
| "loop", | ||
| "game-loop", | ||
| "animation-loop", | ||
| "requestanimationframe", | ||
| "fps", | ||
| "game-loop" | ||
| "fps-limit", | ||
| "fps-limiter", | ||
| "delta-time", | ||
| "tick", | ||
| "render-loop", | ||
| "update-loop", | ||
| "frame-rate", | ||
| "typescript", | ||
| "game-engine" | ||
| ], | ||
| "type": "module", | ||
| "sideEffects": false, | ||
| "main": "./dist/index.umd.js", | ||
| "module": "./dist/index.esm.js", | ||
| "typings": "./dist/index.d.ts", | ||
| "type": "module", | ||
| "types": "./dist/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.umd.js", | ||
| "default": "./dist/index.umd.js" | ||
| }, | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "files": [ | ||
@@ -34,3 +54,3 @@ "dist" | ||
| "@eslint/js": "^10.0.1", | ||
| "@vitest/coverage-v8": "^4.1.4", | ||
| "@vitest/coverage-v8": "^4.1.5", | ||
| "eslint": "^10.2.1", | ||
@@ -41,9 +61,8 @@ "eslint-config-prettier": "^10.1.8", | ||
| "prettier": "^3.8.3", | ||
| "terser": "^5.46.1", | ||
| "typescript": "^6.0.3", | ||
| "typescript-eslint": "^8.58.2", | ||
| "vite": "^8.0.8", | ||
| "typescript-eslint": "^8.59.0", | ||
| "vite": "^8.0.10", | ||
| "vite-plugin-dts": "^4.5.4", | ||
| "vitest": "^4.1.4" | ||
| "vitest": "^4.1.5" | ||
| } | ||
| } |
+23
-6
@@ -8,8 +8,17 @@ # Ticker | ||
| Javascript/typescript library for running app loop with separate logical/drawing ticks and FPS limitation. | ||
| A lightweight, zero-dependency JavaScript/TypeScript library for running an application loop with **separate logic and | ||
| draw ticks**, **FPS limiting**, and **low-FPS detection**. | ||
| <hr> | ||
| ### Why Ticker? | ||
| - π― **Decoupled logic & rendering** β update game state and draw frames independently | ||
| - ποΈ **FPS control** β cap your draw rate to save CPU/battery | ||
| - π **Low-FPS callbacks** β react when performance degrades (e.g. lower visual quality) | ||
| - π§ͺ **Test-friendly** β ships with `TickerMock` for deterministic unit tests | ||
| - π¦ **Zero dependencies** and fully typed | ||
| ### Installation | ||
| ``` | ||
| ```bash | ||
| npm install @armniko/ticker | ||
@@ -21,5 +30,5 @@ ``` | ||
| ```typescript | ||
| import {Ticker, Time} from '@armniko/ticker'; | ||
| import { Ticker, Time } from '@armniko/ticker'; | ||
| const element: { position: { x: number, y: number } } = {position: {x: 0, y: 0}}; | ||
| const element: { position: { x: number, y: number } } = { position: { x: 0, y: 0 } }; | ||
| const animation: { durationMs: number, distancePx: number } = { | ||
@@ -105,5 +114,13 @@ durationMs: 2000, | ||
| <tr> | ||
| <td>v2.2.0</td> | ||
| <td> | ||
| Removed minification of build.<br> | ||
| Added <code>exports</code> field for proper module resolution and types.<br> | ||
| Marked package as side-effect free. | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
| <td>v2.1.1</td> | ||
| <td> | ||
| Update packages. | ||
| Updated packages. | ||
| </td> | ||
@@ -129,3 +146,3 @@ </tr> | ||
| <td> | ||
| Precompile UMD and ESM. | ||
| Precompiled UMD and ESM. | ||
| </td> | ||
@@ -132,0 +149,0 @@ </tr> |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
22288
29.33%12
-7.69%557
376.07%1
-66.67%153
12.5%