Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/nasser/ajeeb-coroutines
Coroutines for the Ajeeb Game Engine
https://github.com/nasser/ajeeb-coroutines
Last synced: 3 months ago
JSON representation
Coroutines for the Ajeeb Game Engine
- Host: GitHub
- URL: https://github.com/nasser/ajeeb-coroutines
- Owner: nasser
- Archived: true
- Created: 2019-08-12T15:28:05.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-06-13T14:13:09.000Z (5 months ago)
- Last Synced: 2024-06-13T17:10:12.709Z (5 months ago)
- Language: TypeScript
- Size: 1.07 MB
- Stars: 20
- Watchers: 3
- Forks: 2
- Open Issues: 11
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Ajeeb Coroutines
Unity-inspired Coroutines for the browser and nodejs.
**All work has moved to the monorepo on sourcehut: https://git.sr.ht/~nasser/ajeeb**
Ajeeb Coroutines are a TypeScript implementation of [a similar idea][unicoro]
from [the Unity 3D engine][unity]. They use [ES6 generators][es6gen] to turn
code that *reads synchronously* into code that *runs across multiple frames*.
They were designed for the [Ajeeb Game Engine][ajeeb] but have no dependencies
and can be used anywhere.## Installation
```
npm install nasser/ajeeb-coroutines
```Or in a browser you can link to the CDN, using either legacy script tags
```html
```
or ES6 modules
```html
import * as coro from "https://cdn.jsdelivr.net/gh/nasser/ajeeb-coroutines@master/build/coroutines.esm.js"
```
## Usage
An instance of an ES6 generator is treated as [*a coroutine*][wikicoro]. An
instance of the [[Schedule]] class schedules and runs coroutines.[[Schedule.add]] adds a couroutine to the collection. [[Schedule.tick]]
runs every coroutine in the collection up to their next [yield][yielddoc]
statement. Each coroutine remembers the last [yield][yielddoc] they reached, and
the next time [[Schedule.tick]] is called they resume execution from that
point.```js
import { Schedule } from "ajeeb-coroutines"let sched = new Schedule()
sched.add(function* () {
console.log("hello") // prints "hello"
yield; // waits until next tick
console.log("world")
console.log("how") // prints "world" and "how"
yield; yield; // waits for two ticks
console.log("are you?") // prints "are you?"
})sched.tick()
// prints "hello"
sched.tick()
// prints "world"
// prints "how"
sched.tick()
// does nothing
sched.tick()
// prints "are you?"
// further calls to sched.tick() will do nothing
```Coroutines are designed to run across multiple frames. [[tick]] can be scheduled
to run regularly [setInterval][si] or [requestAnimationFrame][raf] in a browser.
This advances every coroutine in the collection automatically once per frame.
When scheduled like this, you can think of [yield][yielddoc] as a way of
"waiting one frame".```js
import { Schedule } from "ajeeb-coroutines"let sched = new Schedule()
sched.add(function* () {
console.log("hello") // prints "hello" and waits one frame
yield;
console.log("world") // prints "world" and waits two frames
yield; yield;
console.log("how") // prints "how" and waits three frames
yield; yield; yield;
console.log("are") // prints "are" and waits four frames
yield; yield; yield; yield;
console.log("you?") // prints "you?"
})setInterval(() => sched.tick(), 1000 / 60) // tick 60 times a second
```Generators are normal JavaScript functions. They have access to local variables,
closures, arguments, and more. [yield][yielddoc] can appear anywhere.```js
import { Schedule } from "ajeeb-coroutines"let sched = new Schedule()
function* hello(repeat) {
console.log("hello") // prints "hello" and waits one frame
yield;
for(let i=0; i sched.tick(), 1000 / 60) // tick 60 times a second
```This library also exports a number of generically useful coroutines, like [[wait]],
that can be combined with your own in powerful ways. A coroutine can be made to
wait for another coroutine with the [yield*][yieldstar] statement. If
[yield][yielddoc] is read as "wait one frame" [yield*][yieldstar] is read as
"wait until this other coroutine completes"```js
import { Schedule, wait } from "ajeeb-coroutines"let sched = new Schedule()
// schedule coroutines to tick every frame
// in the browser
function runCoroutines() {
requestAnimationFrame( runCoroutines )
sched.tick()
}
runCoroutines()// in node
setInterval(() => sched.tick(), 1000/60)// you can add coroutines afterwards
sched.add(function* () {
console.log("hello") // prints "hello"
yield* wait(2) // wait for 2 seconds
console.log("world") // prints "world"
yield* wait(3) // waits 3 seconds
console.log("!!!") // prints "!!!"
})// prints "hello" immediately
// waits 2 seconds
// prints "world"
// waits 3 seconds
// prints "!!!"
```Coroutines can be treated as normal functions. They take arguments, and can be as complex as needed.
```js
import fs from "fs"
import { Schedule, waitUntil } from "ajeeb-coroutines"let sched = new Schedule()
function* waitForFile(path) {
console.log("waiting for", path);
yield* waitUntil(() => fs.existsSync(path))
console.log("ok");
}sched.add(waitForFile("nice.txt"))
// in the browser
function runCoroutines() {
requestAnimationFrame( runCoroutines )
sched.tick()
}
runCoroutines()// in node
setInterval(() => sched.tick(), 1000/60)
```[es6gen]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator
[ajeeb]: http://ajeeb.games
[yieldstar]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*
[yielddoc]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
[unity]: https://www.unity3d.com/
[unicoro]: https://docs.unity3d.com/Manual/Coroutines.html
[wikicoro]: https://en.wikipedia.org/wiki/Coroutine
[raf]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
[si]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval