From b5b560f268fa18c51f77f8566de7c3c581733eaa Mon Sep 17 00:00:00 2001 From: naturecodevoid <44983869+naturecodevoid@users.noreply.github.com> Date: Mon, 4 May 2020 01:54:22 -0700 Subject: [PATCH] :zap: ct.timer and (Issue 151) ct.flow, ct.u.wait, ct.tween now operate based on ct.delta, with optional setTimeout mode (#179 by @naturecodevoid) Co-authored-by: Cosmo Myzrail Gorynych --- .gitignore | 180 ++++++++-------- app/data/ct.libs/flow/DOCS.md | 3 + app/data/ct.libs/flow/README.md | 4 +- app/data/ct.libs/flow/index.js | 11 +- app/data/ct.libs/tween/DOCS.md | 1 + app/data/ct.libs/tween/index.js | 52 ++--- .../ct.libs/tween/injects/beforeroomstep.js | 5 +- app/data/ct.release/main.js | 48 +++-- app/data/ct.release/timer.js | 163 +++++++++++++++ package-lock.json | 175 +++++++++------- projects/u.wait_delta.ict | 194 ++++++++++++++++++ .../i17142445-0a78-4191-a02d-528bcd40e136.png | Bin 0 -> 4894 bytes ...5-0a78-4191-a02d-528bcd40e136.png_prev.png | Bin 0 -> 2560 bytes ...0a78-4191-a02d-528bcd40e136.png_prev@2.png | Bin 0 -> 3452 bytes projects/u.wait_delta/img/r0079a0731f6f.png | Bin 0 -> 4037 bytes projects/u.wait_delta/img/r318bf434ecf1.png | Bin 0 -> 4037 bytes .../u.wait_delta/img/sc8c103bdced8_prev.png | Bin 0 -> 305 bytes .../u.wait_delta/img/sc8c103bdced8_prev@2.png | Bin 0 -> 305 bytes projects/u.wait_delta/img/splash.png | Bin 0 -> 4037 bytes src/node_requires/exporter/index.js | 6 +- 20 files changed, 626 insertions(+), 216 deletions(-) create mode 100644 app/data/ct.release/timer.js create mode 100644 projects/u.wait_delta.ict create mode 100644 projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png create mode 100644 projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png_prev.png create mode 100644 projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png_prev@2.png create mode 100644 projects/u.wait_delta/img/r0079a0731f6f.png create mode 100644 projects/u.wait_delta/img/r318bf434ecf1.png create mode 100644 projects/u.wait_delta/img/sc8c103bdced8_prev.png create mode 100644 projects/u.wait_delta/img/sc8c103bdced8_prev@2.png create mode 100644 projects/u.wait_delta/img/splash.png diff --git a/.gitignore b/.gitignore index eb3a634eb..04ae94128 100644 --- a/.gitignore +++ b/.gitignore @@ -1,89 +1,91 @@ -# Mac - -.DS_Store - -# Logs -logs -*.log -npm-debug.log* - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directory -# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git -node_modules -bower_components - -temp/ -desktop\.ini -*.png~ -.directory - -# Generated files -src/typedefs/ct.js/types.d.ts -app/examples -app/data/bundle.js -app/data/bundle.css -app/data/node_requires/**/* -app/data/fonts/style/.css -app/data/theme*.css -app/data/typedefs/global.d.ts -app/data/typedefs/pixi.js.d.ts -/app/data/docs -app/index.html -app/preview.html -app/empty.html -app/debuggerToolbar.html -app/qrCodePanel.html -app/exportDesktop -app/temp -/temp -app/data/fonts/style/.css -app/data/patronsCache.csv -builds -build -cache -tempChangelog.md - -# tests -error_screenshots/ -reports/ - -# ct specific -/export -app/zipexport -app/*.ict.zip -app/Screenshot of *.png -app/export.zip -app/export -*.ict.recovery - -# editor-specific -/.vscode - -# docs -docs/db.json -docs/node_modules -docs/public -app/data/icons.svg -export.zip -app/pleaseCtJSLoadWithoutGPUAccelerationMmkay -app/debugger.html +# Mac + +.DS_Store + +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git +node_modules +bower_components + +temp/ +desktop\.ini +*.png~ +.directory + +# Generated files +src/typedefs/ct.js/types.d.ts +app/examples +app/data/bundle.js +app/data/bundle.css +app/data/node_requires/**/* +app/data/fonts/style/.css +app/data/theme*.css +app/data/typedefs/global.d.ts +app/data/typedefs/pixi.js.d.ts +/app/data/docs +app/index.html +app/preview.html +app/empty.html +app/debuggerToolbar.html +app/qrCodePanel.html +app/exportDesktop +app/temp +/temp +app/data/fonts/style/.css +app/data/patronsCache.csv +builds +build +cache +tempChangelog.md + +# tests +error_screenshots/ +reports/ + +# ct specific +/export +app/zipexport +app/*.ict.zip +app/Screenshot of *.png +app/export.zip +app/export +*.ict.recovery + +# editor-specific +/.vscode + +# docs +docs/db.json +docs/node_modules +docs/public +app/data/icons.svg +export.zip +app/pleaseCtJSLoadWithoutGPUAccelerationMmkay +app/debugger.html + +**/**/*.orig diff --git a/app/data/ct.libs/flow/DOCS.md b/app/data/ct.libs/flow/DOCS.md index 327654b9c..8b4a46d5f 100644 --- a/app/data/ct.libs/flow/DOCS.md +++ b/app/data/ct.libs/flow/DOCS.md @@ -96,9 +96,12 @@ Similar to `ct.flow.delay`, this method will return a new function that will lim the execution of the `func` to max once in `ms` period. It will call the function first and then block the execution for `ms` time, though. +It takes into account `ct.delta` or `ct.deltaUi`. + **Returns**: `function` - a new triggerable function | Param | Type | Description | | --- | --- | --- | | func | `function` | The function to limit | | ms | `Number` | The period to wait, in milliseconds | +| [useUiDelta=false] | `Boolean` | If true, use `ct.deltaUi` instead of `ct.delta` | diff --git a/app/data/ct.libs/flow/README.md b/app/data/ct.libs/flow/README.md index e37f59986..e7c673d3a 100644 --- a/app/data/ct.libs/flow/README.md +++ b/app/data/ct.libs/flow/README.md @@ -1,3 +1 @@ -A collection of high-level utilities for flow control, that are especially useful while working with asynchronous events. - -Please note that this function **ignores the scaling of `ct.delta`**, meaning that triggers will work even while the game is paused. \ No newline at end of file +A collection of high-level utilities for flow control, that are especially useful while working with asynchronous events. \ No newline at end of file diff --git a/app/data/ct.libs/flow/index.js b/app/data/ct.libs/flow/index.js index b489f849d..83735d46e 100644 --- a/app/data/ct.libs/flow/index.js +++ b/app/data/ct.libs/flow/index.js @@ -140,16 +140,21 @@ * * @param {Function} func The function to limit * @param {Number} ms The period to wait, in milliseconds + * @param {boolean} [useUiDelta=false] If true, use ct.deltaUi instead of ct.delta * @returns {Function} a new triggerable function */ - timer(func, ms) { + timer(func, ms, useUiDelta = false) { // The same may be done with ct.flow.gate + ct.flow. var timer; var delay = function () { if (!timer) { - timer = setTimeout(() => { + timer = true; + ct.u.wait(ms, useUiDelta).then(() => { timer = false; - }, ms); + }); + /*timer = setTimeout(() => { + timer = false; + }, ms);*/ func(); } }; diff --git a/app/data/ct.libs/tween/DOCS.md b/app/data/ct.libs/tween/DOCS.md index 7f1d58bd6..75ae1b946 100644 --- a/app/data/ct.libs/tween/DOCS.md +++ b/app/data/ct.libs/tween/DOCS.md @@ -7,6 +7,7 @@ Creates a new tween effect and adds it to the game loop. * `options.fields` A map with pairs `fieldName: newValue`. Values must be of numerical type. * `options.curve` An interpolating function. You can write your own, or use default ones written below. The default one is `ct.tween.ease`. * `options.duration` The duration of easing, in milliseconds. + * `options.useUiDelta` If true, use `ct.deltaUi` instead of `ct.delta`. The default is `false`. Returns a Promise which is resolved if the effect was fully played, or rejected if it was interrupted manually by code, room switching or Copy kill. diff --git a/app/data/ct.libs/tween/index.js b/app/data/ct.libs/tween/index.js index cf4531cb5..88987dc38 100644 --- a/app/data/ct.libs/tween/index.js +++ b/app/data/ct.libs/tween/index.js @@ -1,17 +1,18 @@ -/* global ct */ +/* global CtTimer */ ct.tween = { /** * Creates a new tween effect and adds it to the game loop - * + * * @param {Object} options An object with options: * @param {Object|Copy} options.obj An object to animate. All objects are supported. * @param {Object} options.fields A map with pairs `fieldName: newValue`. Values must be of numerical type. - * @param {Function} options.curve An interpolating function. You can write your own, - * or use default ones written below. The default one is `ct.tween.ease`. + * @param {Function} options.curve An interpolating function. You can write your own, + * or use default ones (see methods in `ct.tween`). The default one is `ct.tween.ease`. * @param {Number} options.duration The duration of easing, in milliseconds. - * - * @returns {Promise} A promise which is resolved if the effect was fully played, + * @param {Number} options.useUiDelta If true, use ct.deltaUi instead of ct.delta. The default is `false`. + * + * @returns {Promise} A promise which is resolved if the effect was fully played, * or rejected if it was interrupted manually by code, room switching or instance kill. * You can call a `stop()` method on this promise to interrupt it manually. */ @@ -21,7 +22,8 @@ ct.tween = { fields: options.fields || {}, curve: options.curve || ct.tween.ease, duration: options.duration || 1000, - registered: (Number(new Date())) + useUiDelta: options.useUiDelta || false, + timer: new CtTimer('ct.tween', this.duration, this.useUiDelta) }; var promise = new Promise((resolve, reject) => { tween.resolve = resolve; @@ -44,8 +46,8 @@ ct.tween = { /** * Linear interpolation. * Here and below, these parameters are used: - * - * @param {Number} s Starting value + * + * @param {Number} s Starting value * @param {Number} d The change of value to transition to, the Delta * @param {Number} a The current timing state, 0-1 * @returns {Number} Interpolated value @@ -56,61 +58,61 @@ ct.tween = { ease(s, d, a) { a *= 2; if (a < 1) { - return d/2*a*a + s; + return d / 2 * a * a + s; } a--; - return -d/2 * (a*(a-2) - 1) + s; + return -d / 2 * (a * (a - 2) - 1) + s; }, easeInQuad(s, d, a) { - return d*a*a + s; + return d * a * a + s; }, easeOutQuad(s, d, a) { - return -d * a*(a-2) + s; + return -d * a * (a - 2) + s; }, easeInCubic(s, d, a) { - return d*a*a*a + s; + return d * a * a * a + s; }, easeOutCubic(s, d, a) { a--; - return d*(a*a*a + 1) + s; + return d * (a * a * a + 1) + s; }, easeInOutCubic(s, d, a) { a *= 2; if (a < 1) { - return d/2*a*a*a + s; + return d / 2 * a * a * a + s; } a -= 2; - return d/2*(a*a*a + 2) + s; + return d / 2 * (a * a * a + 2) + s; }, easeInOutQuart(s, d, a) { a *= 2; if (a < 1) { - return d/2*a*a*a*a + s; + return d / 2 * a * a * a * a + s; } a -= 2; - return -d/2 * (a*a*a*a - 2) + s; + return -d / 2 * (a * a * a * a - 2) + s; }, easeInQuart(s, d, a) { - return d*a*a*a*a + s; + return d * a * a * a * a + s; }, easeOutQuart(s, d, a) { a--; - return -d * (a*a*a*a - 1) + s; + return -d * (a * a * a * a - 1) + s; }, easeInCirc(s, d, a) { - return -d * (Math.sqrt(1 - a*a) - 1) + s; + return -d * (Math.sqrt(1 - a * a) - 1) + s; }, easeOutCirc(s, d, a) { a--; - return d * Math.sqrt(1 - a*a) + s; + return d * Math.sqrt(1 - a * a) + s; }, easeInOutCirc(s, d, a) { a *= 2; if (a < 1) { - return -d/2 * (Math.sqrt(1 - a*a) - 1) + s; + return -d / 2 * (Math.sqrt(1 - a * a) - 1) + s; } a -= 2; - return d/2 * (Math.sqrt(1 - a*a) + 1) + s; + return d / 2 * (Math.sqrt(1 - a * a) + 1) + s; }, tweens: [], wait: ct.u.wait diff --git a/app/data/ct.libs/tween/injects/beforeroomstep.js b/app/data/ct.libs/tween/injects/beforeroomstep.js index 112ad9b08..3b47e264f 100644 --- a/app/data/ct.libs/tween/injects/beforeroomstep.js +++ b/app/data/ct.libs/tween/injects/beforeroomstep.js @@ -1,7 +1,4 @@ -/* global ct */ - var i = 0; -var newTime = Number(new Date()); while (i < ct.tween.tweens.length) { var tween = ct.tween.tweens[i]; if (tween.obj.kill) { @@ -12,7 +9,7 @@ while (i < ct.tween.tweens.length) { ct.tween.tweens.splice(i, 1); continue; } - var a = (newTime - tween.registered) / tween.duration; + var a = tween.timer.time / tween.duration; if (a > 1) { a = 1; } diff --git a/app/data/ct.release/main.js b/app/data/ct.release/main.js index c39510faa..7cbd3cc89 100644 --- a/app/data/ct.release/main.js +++ b/app/data/ct.release/main.js @@ -1,4 +1,7 @@ /* Made with ct.js http://ctjs.rocks/ */ + +/* global CtTimer */ + const deadPool = []; // a pool of `kill`-ed copies for delaying frequent garbage collection const copyTypeSymbol = Symbol('I am a ct.js copy'); setInterval(function () { @@ -45,9 +48,9 @@ const ct = { * This is a version for UI elements, as it is not affected by time scaling, and thus works well * both with slow-mo effects and game pause. * - * @type {number} - */ - deltaUi: 1, + * @type {number} + */ + deltaUi: 1, /** * The camera that outputs its view to the renderer. * @type {Camera} @@ -147,7 +150,7 @@ try { console.error(e); // eslint-disable-next-line no-console console.warn('[ct.js] Something bad has just happened. This is usually due to hardware problems. I\'ll try to fix them now, but if the game still doesn\'t run, try including a legacy renderer in the project\'s settings.'); - PIXI.settings.SPRITE_MAX_TEXTURES = Math.min(PIXI.settings.SPRITE_MAX_TEXTURES , 16); + PIXI.settings.SPRITE_MAX_TEXTURES = Math.min(PIXI.settings.SPRITE_MAX_TEXTURES, 16); ct.pixiApp = new PIXI.Application(pixiAppSettings); } @@ -289,7 +292,7 @@ ct.u = { * @returns {number} The result of the interpolation */ lerp(a, b, alpha) { - return a + (b-a)*alpha; + return a + (b - a) * alpha; }, /** * Returns the position of a given value in a given range. Opposite to linear interpolation. @@ -361,7 +364,7 @@ ct.u = { * @param {any} [arr] An optional array of properties to copy. If not specified, all the properties will be copied. * @returns {object} The modified destination object */ - ext (o1, o2, arr) { + ext(o1, o2, arr) { if (arr) { for (const i in arr) { if (o2[arr[i]]) { @@ -390,22 +393,26 @@ ct.u = { document.getElementsByTagName('head')[0].appendChild(script); }, /** - * Returns a Promise that resolves after the given time + * Returns a Promise that resolves after the given time. + * This timer is run in gameplay time scale, meaning that it is affected by time stretching. * @param {number} time Time to wait, in milliseconds - * @returns {Promise} The promise with no data + * @returns {CtTimer} The timer, which you can call `.then()` to */ wait(time) { - var room = ct.room.name; - return new Promise((resolve, reject) => setTimeout(() => { - if (ct.room.name === room) { - resolve(); - } else { - reject({ - info: 'Room switch', - from: 'ct.u.wait' - }); - } - }, time)); + const id = ct.timer.counter; + ct.timer.counter++; + return new CtTimer('ct.u.wait' + id, time); + }, + /** + * Returns a Promise that resolves after the given time. + * This timer runs in UI time scale and is not sensitive to time stretching. + * @param {number} time Time to wait, in milliseconds + * @returns {CtTimer} The timer, which you can call `.then()` to + */ + waitUi(time) { + const id = ct.timer.counter; + ct.timer.counter++; + return new CtTimer('ct.u.wait' + id, time, true); } }; ct.u.ext(ct.u, {// make aliases @@ -449,10 +456,11 @@ ct.u.ext(ct.u, {// make aliases } }; - ct.loop = function(delta) { + ct.loop = function (delta) { ct.delta = delta; ct.deltaUi = PIXI.Ticker.shared.elapsedMS / (1000 / (PIXI.Ticker.shared.maxFPS || 60)); ct.inputs.updateActions(); + ct.timer.updateTimers(); for (let i = 0, li = ct.stack.length; i < li; i++) { ct.types.beforeStep.apply(ct.stack[i]); ct.stack[i].onStep.apply(ct.stack[i]); diff --git a/app/data/ct.release/timer.js b/app/data/ct.release/timer.js new file mode 100644 index 000000000..5937c7238 --- /dev/null +++ b/app/data/ct.release/timer.js @@ -0,0 +1,163 @@ +(function () { + const ctTimerTime = Symbol('time'); + const ctTimerRoomName = Symbol('roomName'); + const ctTimerTimeLeftOriginal = Symbol('timeLeftOriginal'); + const promiseResolve = Symbol('promiseResolve'); + const promiseReject = Symbol('promiseReject'); + + /** + * @property {boolean} isUi Whether the timer uses ct.deltaUi or not. + * @property {string|false} name The name of the timer + */ + class CtTimer { + /** + * An object for holding a timer + * + * @param {number} timeMs The length of the timer, **in milliseconds** + * @param {string|false} [name=false] The name of the timer + * @param {boolean} [uiDelta=false] If `true`, it will use `ct.deltaUi` for counting time. if `false`, it will use `ct.delta` for counting time. + */ + constructor(timeMs, name = false, uiDelta = false) { + this[ctTimerRoomName] = ct.room.name || ''; + this.name = name && name.toString(); + this.isUi = uiDelta; + this[ctTimerTime] = 0; + this[ctTimerTimeLeftOriginal] = timeMs; + this.timeLeft = this[ctTimerTimeLeftOriginal]; + this.promise = new Promise((resolve, reject) => { + this[promiseResolve] = resolve; + this[promiseReject] = reject; + }); + this.rejected = false; + this.done = false; + this.settled = false; + ct.timer.timers.add(this); + } + + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * + * @param {Function} onfulfilled The callback to execute when the Promise is resolved. + * @param {Function} [onrejected] The callback to execute when the Promise is rejected. + * @returns {Promise} A Promise for the completion of which ever callback is executed. + */ + then(...args) { + return this.promise.then(...args); + } + /** + * Attaches a callback for the rejection of the Promise. + * + * @param {Function} [onrejected] The callback to execute when the Promise is rejected. + * @returns {Promise} A Promise for the completion of which ever callback is executed. + */ + catch(onrejected) { + return this.promise.catch(onrejected); + } + + /** + * The time passed on this timer, in seconds + * @type {number} + */ + get time() { + return this[ctTimerTime] * 1000 / ct.speed; + } + set time(newTime) { + this[ctTimerTime] = newTime / 1000 * ct.speed; + } + + /** + * Updates the timer. **DONT CALL THIS UNLESS YOU KNOW WHAT YOU ARE DOING** + * + * @returns {void} + * @private + */ + update() { + // Not something that would normally happen, + // but do check whether this timer was not automatically removed + if (this.rejected === true || this.done === true) { + this.remove(); + return; + } + this[ctTimerTime] += this.isUi ? ct.deltaUi : ct.delta; + if (ct.room.name !== this[ctTimerRoomName] && this[ctTimerRoomName] !== '') { + this.reject({ + info: 'Room switch', + from: 'ct.timer' + }); // Reject if the room was switched + } + + // If the timer is supposed to end + if (this.timeLeft !== 0) { + this.timeLeft = this[ctTimerTimeLeftOriginal] - this.time; + if (this.timeLeft <= 0) { + this.resolve(); + } + } + } + + /** + * Instantly triggers the timer and calls the callbacks added through `then` method. + * @returns {void} + */ + resolve() { + this.done = true; + this.settled = true; + this[promiseResolve](); + this.remove(); + } + /** + * Stops the timer with a given message by rejecting a Promise object. + * @param {any} message The value to pass to the `catch` callback + * @returns {void} + */ + reject(message) { + this.rejected = true; + this.settled = true; + this[promiseReject](message); + this.remove(); + } + /** + * Removes the timer from ct.js game loop. This timer will not trigger. + * @returns {void} + */ + remove() { + ct.timer.timers.delete(this); + } + } + window.CtTimer = CtTimer; + + /** + * Timer utilities + * @namespace + */ + ct.timer = { + /** + * A set with all the active timers. + * @type Set + */ + timers: new Set(), + counter: 0, + /** + * Adds a new timer with a given name + * + * @param {string|false} name The name of the timer, which you use to access it from `ct.timer.timers`. + * @param {number} [timeMs=0] The length of the timer, **in milliseconds** + * @param {boolean} [uiDelta=false] If `true`, it will use `ct.deltaUi` for counting time. if `false`, it will use `ct.delta` for counting time. + * @returns {CtTimer} The timer + */ + add(name=false, timeMs = 0, uiDelta = false) { + return new CtTimer(name, timeMs, uiDelta, true); + }, + /** + * Updates the timers. **DONT CALL THIS UNLESS YOU KNOW WHAT YOU ARE DOING** + * + * @returns {void} + * @private + */ + updateTimers() { + for (const timer of this.timers) { + timer.update(); + } + } + }; +})(); diff --git a/package-lock.json b/package-lock.json index b87799b3d..2545a9d8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1692,9 +1692,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3215,9 +3215,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3341,22 +3341,26 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "optional": true }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "optional": true, "requires": { "delegates": "^1.0.0", @@ -3365,12 +3369,14 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "optional": true }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "optional": true, "requires": { "balanced-match": "^1.0.0", @@ -3384,22 +3390,26 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "optional": true }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { @@ -3412,17 +3422,20 @@ }, "deep-extend": { "version": "0.6.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { @@ -3435,12 +3448,14 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { "aproba": "^1.0.3", @@ -3468,12 +3483,14 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.24", - "bundled": true, + "resolved": false, + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -3489,7 +3506,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { "once": "^1.3.0", @@ -3503,12 +3521,14 @@ }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "optional": true, "requires": { "number-is-nan": "^1.0.0" @@ -3516,12 +3536,14 @@ }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "optional": true, "requires": { "brace-expansion": "^1.1.7" @@ -3623,7 +3645,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -3634,17 +3657,20 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "optional": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "optional": true, "requires": { "wrappy": "1" @@ -3652,17 +3678,20 @@ }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -3671,7 +3700,8 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { @@ -3681,7 +3711,8 @@ }, "rc": { "version": "1.2.8", - "bundled": true, + "resolved": false, + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "optional": true, "requires": { "deep-extend": "^0.6.0", @@ -3714,17 +3745,20 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "optional": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { @@ -3734,17 +3768,20 @@ }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "optional": true, "requires": { "code-point-at": "^1.0.0", @@ -3754,7 +3791,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -3762,7 +3800,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "optional": true, "requires": { "ansi-regex": "^2.0.0" @@ -3770,7 +3809,8 @@ }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { @@ -3925,9 +3965,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5082,9 +5122,9 @@ } }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "has-value": { "version": "1.0.0", @@ -5938,14 +5978,14 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7219,13 +7259,6 @@ "function-bind": "^1.1.1", "has-symbols": "^1.0.0", "object-keys": "^1.0.11" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - } } }, "object.defaults": { @@ -7392,9 +7425,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -9903,9 +9936,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", diff --git a/projects/u.wait_delta.ict b/projects/u.wait_delta.ict new file mode 100644 index 000000000..70f3bdc06 --- /dev/null +++ b/projects/u.wait_delta.ict @@ -0,0 +1,194 @@ +ctjsVersion: 1.3.0 +notes: /* empty */ +libs: + place: + gridX: 1024 + gridY: 1024 + fittoscreen: + mode: scaleFit + mouse: {} + keyboard: {} + keyboard.polyfill: {} + sound.howler: {} + flow: {} + tween: {} +textures: + - name: Robot_Idle + untill: 0 + grid: + - 1 + - 1 + axis: + - 0 + - 0 + marginx: 0 + marginy: 0 + imgWidth: 96 + imgHeight: 96 + width: 96 + height: 96 + offx: 0 + offy: 0 + origname: i17142445-0a78-4191-a02d-528bcd40e136.png + source: >- + /Users/aidandj/Library/Mobile + Documents/com~apple~CloudDocs/Code/ct-js/src/examples/Platformer_assets/Robot_Idle.png + shape: rect + left: 0 + right: 96 + top: 0 + bottom: 96 + uid: 17142445-0a78-4191-a02d-528bcd40e136 + padding: 1 +skeletons: [] +types: + - name: test + depth: 0 + oncreate: |- + ct.tween.add({ + obj: this, + fields: { + x: this.x + 100, + y: this.y + 150 + }, + duration: 1000, + curve: ct.tween.easeInOutCirc + }); + onstep: this.move(); + ondraw: '' + ondestroy: '' + uid: 52954eac-7257-4f70-a490-0e46be2914e7 + texture: 17142445-0a78-4191-a02d-528bcd40e136 + extends: {} + lastmod: 1587492564967 +sounds: [] +styles: + - name: default + uid: ff53e951-ccf0-481c-bf41-c8c103bdced8 + origname: sc8c103bdced8 + font: + family: sans-serif + size: 12 + weight: 400 + italic: false + lastmod: 1586047198425 + fill: + type: '0' +rooms: + - name: test + oncreate: |2- + this.text = new PIXI.Text('delta: ' + ct.delta + "\ndeltaUi: " + ct.deltaUi + "\ntimerOn: " + this.timerOn, ct.styles.get('default')); + this.text.x = 32; + this.text.y = 32; + + this.addChild(this.text); + + this.timerOn = false; + this.timerAdded = false; + + this.timer = new CtTimer("a", 5000, true).then(() => { + console.warn("ajshdjakshdjahskjdhjkh +++++++++++++++++++"); + }); + + this.flowTimer = ct.flow.timer(() => { + console.warn("a"); + }, 5000); + onstep: '' + ondraw: |2- + if (ct.actions.Test.down) { + //ct.delta = 0; + //ct.deltaUi = 0; + if (this.timerOn == false) { + this.timerOn = true; + ct.u.wait(1000).then(() => { + this.timerOn = false; + }); + } + if (this.timerAdded == false) { + //ct.timer.addTimer("a"); + this.timerAdded = true; + } + } + console.log(this.timerOn); + console.log(ct.timer.timers["a"]); + if (this.timerOn == false) { + this.timerOn = true; + ct.u.wait(5000).then(() => { + console.warn("done yay"); + //this.timerOn = false; + }); + } + this.flowTimer(); + //console.log(ct.timer._timersInternal["ct.u.wait"] / 60); + + this.text.x = 32; + this.text.y = 32; + this.text.text = 'delta: ' + ct.delta + "\ndeltaUi: " + ct.deltaUi + "\ntimerOn: " + this.timerOn; + onleave: '' + width: 800 + height: 600 + backgrounds: [] + copies: + - x: 128 + 'y': 64 + uid: 52954eac-7257-4f70-a490-0e46be2914e7 + tiles: + - depth: -10 + tiles: [] + uid: ef9f0643-be19-44d7-8ff1-0079a0731f6f + thumbnail: 0079a0731f6f + gridX: 64 + gridY: 64 + lastmod: 1587428032702 + - name: test2 + oncreate: '' + onstep: '' + ondraw: '' + onleave: '' + width: 800 + height: 600 + backgrounds: [] + copies: [] + tiles: + - depth: -10 + tiles: [] + uid: cfcbbd02-8895-4083-885d-318bf434ecf1 + thumbnail: 318bf434ecf1 + gridX: 64 + gridY: 64 + lastmod: 1587428043720 +actions: + - name: Test + methods: + - code: mouse.Left + multiplier: 1 + - code: keyboard.KeyT +emitterTandems: [] +starting: 0 +settings: + minifyhtmlcss: false + minifyjs: false + fps: 60 + version: + - 0 + - 0 + - 0 + versionPostfix: '' + usePixiLegacy: true + export: + windows: true + linux: true + mac: true + branding: + icon: -1 + accent: '#446adb' + invertPreloaderScheme: true + title: u.wait_delta + author: naturecodevoid + site: 'https://ctjs.rocks' + maxFPS: 60 +scripts: [] +fonts: [] +styletick: .nan +palette: [] +startroom: ef9f0643-be19-44d7-8ff1-0079a0731f6f diff --git a/projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png b/projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png new file mode 100644 index 0000000000000000000000000000000000000000..fa3723f9c70cfbf3ee1b889f9d5cfab9aedb4ae2 GIT binary patch literal 4894 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 HnE3wzhs2#S literal 0 HcmV?d00001 diff --git a/projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png_prev.png b/projects/u.wait_delta/img/i17142445-0a78-4191-a02d-528bcd40e136.png_prev.png new file mode 100644 index 0000000000000000000000000000000000000000..a187a3947b2dc0cef80f908a081b3c0b26c8c321 GIT binary patch literal 2560 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 { 'rooms.js', 'sound.js', 'styles.js', - 'types.js' + 'types.js', + 'timer.js' ]; for (const file of sourcesList) { sources[file] = fs.readFile(path.join(basePath, 'ct.release', file), { @@ -238,6 +239,9 @@ const exportCtProject = async (project, projdir) => { buffer += (await sources['sound.js']) .replace('/*@sound@*/', sounds); + buffer += (await sources['timer.js']); + buffer += '\n'; + const fonts = await bundleFonts(currentProject, projdir, writeDir); buffer += fonts.js; /* eslint-enable require-atomic-updates */