@typeonce/ritmo-browser 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/BrowserHostClock.d.ts +23 -0
- package/dist/BrowserHostClock.d.ts.map +1 -0
- package/dist/BrowserHostClock.js +3 -0
- package/dist/BrowserHostClock.js.map +1 -0
- package/dist/FixedLoop.d.ts +6 -2
- package/dist/FixedLoop.d.ts.map +1 -1
- package/dist/FixedLoop.js +7 -17
- package/dist/FixedLoop.js.map +1 -1
- package/dist/InputCapture.d.ts +1 -1
- package/dist/InputCapture.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/BrowserHostClock.ts +22 -0
- package/src/FixedLoop.ts +13 -9
- package/src/InputCapture.ts +1 -1
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# `@typeonce/ritmo-browser`
|
|
2
2
|
|
|
3
|
+
Migrating from bevy-ts? See the [package migration guide](https://github.com/typeonce-dev/ritmo/blob/main/MIGRATION.md).
|
|
4
|
+
|
|
3
5
|
Browser integrations for ritmo: a fixed-step game loop (`FixedLoop`), keyboard actions with press/release edges, bound by character or by physical key (`Keyboard`), mouse and pen position and button edges over an element (`Pointer`), on-screen touch controls with a floating stick and drag-to-aim buttons (`Touch`), scripted and recorded keyboard and pointer timelines for tests and replays, and a system that copies input into a resource (`InputCapture`).
|
|
4
6
|
|
|
5
7
|
```sh
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser's monotonic clock as a core `HostClock`.
|
|
3
|
+
*
|
|
4
|
+
* `window.performance.now()` never goes backwards, unlike `Date.now`
|
|
5
|
+
* (`HostClock.standard`). The window is passed in, so nothing reads a global.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const runtime = Game.Runtime.make({ services, debug: { hostClock: BrowserHostClock.make(window) } })
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @module BrowserHostClock
|
|
13
|
+
*/
|
|
14
|
+
import type { HostClock } from "@typeonce/ritmo";
|
|
15
|
+
/** What the clock needs from the window. */
|
|
16
|
+
export interface Host {
|
|
17
|
+
readonly performance: {
|
|
18
|
+
readonly now: () => number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** A host clock reading `host.performance.now()`. */
|
|
22
|
+
export declare const make: (host: Host) => HostClock.HostClock;
|
|
23
|
+
//# sourceMappingURL=BrowserHostClock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrowserHostClock.d.ts","sourceRoot":"","sources":["../src/BrowserHostClock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,4CAA4C;AAC5C,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAA;KAAE,CAAA;CACrD;AAED,qDAAqD;AACrD,eAAO,MAAM,IAAI,SAAU,IAAI,KAAG,SAAS,CAAC,SAAoD,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrowserHostClock.js","sourceRoot":"","sources":["../src/BrowserHostClock.ts"],"names":[],"mappings":"AAoBA,qDAAqD;AACrD,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAU,EAAuB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA"}
|
package/dist/FixedLoop.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @module FixedLoop
|
|
9
9
|
* @docGroup browser
|
|
10
10
|
*/
|
|
11
|
+
import type * as Clock from "@typeonce/ritmo/Clock";
|
|
11
12
|
import * as Result from "@typeonce/ritmo/Result";
|
|
12
13
|
/** One renderer or browser tick measured in milliseconds. */
|
|
13
14
|
export interface Tick {
|
|
@@ -23,8 +24,11 @@ export interface TickSource<TTick extends Tick = Tick> {
|
|
|
23
24
|
}
|
|
24
25
|
/** Validated fixed-step timing policy. */
|
|
25
26
|
export interface Options {
|
|
26
|
-
/**
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* The fixed step every update advances (`Clock.hz(60)`): the same value
|
|
29
|
+
* the game's clock resource runs at, so the loop and the clock agree.
|
|
30
|
+
*/
|
|
31
|
+
readonly step: Clock.Step;
|
|
28
32
|
/** Maximum host-frame duration admitted into the accumulator. */
|
|
29
33
|
readonly maxFrameSeconds: number;
|
|
30
34
|
/** Maximum number of simulation updates performed for one host frame. */
|
package/dist/FixedLoop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FixedLoop.d.ts","sourceRoot":"","sources":["../src/FixedLoop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAA;AAEhD,6DAA6D;AAC7D,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,IAAI,CAAA;CACb;AAED,iFAAiF;AACjF,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,IAAI,GAAG,IAAI;IACnD,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,YAAY,CAAA;CACvD;AAED,0CAA0C;AAC1C,MAAM,WAAW,OAAO;IACtB
|
|
1
|
+
{"version":3,"file":"FixedLoop.d.ts","sourceRoot":"","sources":["../src/FixedLoop.ts"],"names":[],"mappings":"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"}
|
package/dist/FixedLoop.js
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Deterministic fixed-step timing for browser and renderer hosts.
|
|
3
|
-
*
|
|
4
|
-
* The loop owns the timing policy that is easy to get subtly wrong in every
|
|
5
|
-
* game: frame clamping, catch-up limits, interpolation, cancellation, and
|
|
6
|
-
* typed update failures. It does not know about an ECS runtime or renderer.
|
|
7
|
-
*
|
|
8
|
-
* @module FixedLoop
|
|
9
|
-
* @docGroup browser
|
|
10
|
-
*/
|
|
11
1
|
import * as Result from "@typeonce/ritmo/Result";
|
|
12
2
|
/** Wraps a host-specific subscription function in the canonical source type. */
|
|
13
3
|
export const source = (subscribe) => ({ subscribe });
|
|
14
4
|
const validate = (options) => {
|
|
15
|
-
for (const field of ["
|
|
5
|
+
for (const field of ["maxFrameSeconds"]) {
|
|
16
6
|
const value = options[field];
|
|
17
7
|
if (!Number.isFinite(value) || value <= 0) {
|
|
18
8
|
return Result.failure({
|
|
@@ -72,24 +62,24 @@ export const start = (options) => {
|
|
|
72
62
|
let droppedSeconds = rawSeconds - elapsedSeconds;
|
|
73
63
|
accumulator += elapsedSeconds;
|
|
74
64
|
let fixedSteps = 0;
|
|
75
|
-
while (accumulator >= options.
|
|
76
|
-
const update = options.update(options.
|
|
65
|
+
while (accumulator >= options.step.dt && fixedSteps < options.maxStepsPerFrame) {
|
|
66
|
+
const update = options.update(options.step.dt);
|
|
77
67
|
if (!update.ok) {
|
|
78
68
|
fail({ kind: "UpdateFailure", error: update.error });
|
|
79
69
|
return;
|
|
80
70
|
}
|
|
81
|
-
accumulator -= options.
|
|
71
|
+
accumulator -= options.step.dt;
|
|
82
72
|
fixedSteps += 1;
|
|
83
73
|
}
|
|
84
|
-
if (accumulator >= options.
|
|
85
|
-
const droppedWholeSteps = Math.floor(accumulator / options.
|
|
74
|
+
if (accumulator >= options.step.dt) {
|
|
75
|
+
const droppedWholeSteps = Math.floor(accumulator / options.step.dt) * options.step.dt;
|
|
86
76
|
accumulator -= droppedWholeSteps;
|
|
87
77
|
droppedSeconds += droppedWholeSteps;
|
|
88
78
|
}
|
|
89
79
|
options.render({
|
|
90
80
|
elapsedSeconds,
|
|
91
81
|
fixedSteps,
|
|
92
|
-
alpha: accumulator / options.
|
|
82
|
+
alpha: accumulator / options.step.dt,
|
|
93
83
|
droppedSeconds
|
|
94
84
|
});
|
|
95
85
|
};
|
package/dist/FixedLoop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FixedLoop.js","sourceRoot":"","sources":["../src/FixedLoop.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FixedLoop.js","sourceRoot":"","sources":["../src/FixedLoop.ts"],"names":[],"mappings":"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"}
|
package/dist/InputCapture.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ export interface Options<S extends Schema.Any, Service extends ServiceDescriptor
|
|
|
64
64
|
/**
|
|
65
65
|
* The generated system. It requires the source service and the resource.
|
|
66
66
|
*/
|
|
67
|
-
export type CaptureSystem<S extends Schema.Any, Root, Needs extends ServiceDescriptor | ResourceDescriptor | ConditionNeedsFromConditions<ReadonlyArray<Condition>>> = Schema.BoundSystem<S, Root, any,
|
|
67
|
+
export type CaptureSystem<S extends Schema.Any, Root, Needs extends ServiceDescriptor | ResourceDescriptor | ConditionNeedsFromConditions<ReadonlyArray<Condition>>> = Schema.BoundSystem<S, Root, any, never, string, Needs>;
|
|
68
68
|
/**
|
|
69
69
|
* Builds the system that writes `source.snapshot()` into `resource`.
|
|
70
70
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputCapture.d.ts","sourceRoot":"","sources":["../src/InputCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,MAAM,CAAC,KAAK;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAA;CAC/B;AAED,KAAK,iBAAiB,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;AAC3D,KAAK,kBAAkB,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;AAE7D;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,iBAAiB,IACtD,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,KAAK,GAAG,KAAK,CAAA;AAEvE,MAAM,WAAW,OAAO,CACtB,CAAC,SAAS,MAAM,CAAC,GAAG,EACpB,OAAO,SAAS,iBAAiB,EACjC,QAAQ,SAAS,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAC7C,IAAI,SAAS,aAAa,CAAC,SAAS,CAAC,GAAG,SAAS,EAAE;IAEnD,uBAAuB;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,GAAG,4CAA4C,CAAA;IACvH,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;IACjF;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,SAAS,iBAAiB,GAAG,kBAAkB,GAAG,4BAA4B,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,IACjK,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"InputCapture.d.ts","sourceRoot":"","sources":["../src/InputCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,MAAM,CAAC,KAAK;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAA;CAC/B;AAED,KAAK,iBAAiB,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;AAC3D,KAAK,kBAAkB,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;AAE7D;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,iBAAiB,IACtD,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,KAAK,GAAG,KAAK,CAAA;AAEvE,MAAM,WAAW,OAAO,CACtB,CAAC,SAAS,MAAM,CAAC,GAAG,EACpB,OAAO,SAAS,iBAAiB,EACjC,QAAQ,SAAS,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAC7C,IAAI,SAAS,aAAa,CAAC,SAAS,CAAC,GAAG,SAAS,EAAE;IAEnD,uBAAuB;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,GAAG,4CAA4C,CAAA;IACvH,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;IACjF;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,SAAS,iBAAiB,GAAG,kBAAkB,GAAG,4BAA4B,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,IACjK,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;AAExD;;GAEG;AACH,eAAO,MAAM,MAAM,GACjB,CAAC,SAAS,MAAM,CAAC,GAAG,EACpB,IAAI,EACJ,KAAK,CAAC,OAAO,SAAS,iBAAiB,EACvC,KAAK,CAAC,QAAQ,SAAS,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,EACnD,KAAK,CAAC,IAAI,SAAS,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,EAAE,QAEzD,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,WACjB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,KAC3C,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAOiB,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Browser host integrations kept outside the renderer-agnostic ECS core. */
|
|
2
|
+
export * as BrowserHostClock from "./BrowserHostClock.ts";
|
|
2
3
|
export * as FixedLoop from "./FixedLoop.ts";
|
|
3
4
|
export * as InputCapture from "./InputCapture.ts";
|
|
4
5
|
export * as Keyboard from "./Keyboard.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAEnC,eAAO,MAAM,UAAU,EAAG,SAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAEnC,eAAO,MAAM,UAAU,EAAG,SAAkB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Browser host integrations kept outside the renderer-agnostic ECS core. */
|
|
2
|
+
export * as BrowserHostClock from "./BrowserHostClock.js";
|
|
2
3
|
export * as FixedLoop from "./FixedLoop.js";
|
|
3
4
|
export * as InputCapture from "./InputCapture.js";
|
|
4
5
|
export * as Keyboard from "./Keyboard.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAEnC,MAAM,CAAC,MAAM,UAAU,GAAG,SAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAEnC,MAAM,CAAC,MAAM,UAAU,GAAG,SAAkB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typeonce/ritmo-browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Browser fixed-step loop, keyboard actions, and input capture for Ritmo",
|
|
5
5
|
"author": "Sandro Maglione",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"provenance": true
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@typeonce/ritmo": "^0.
|
|
50
|
+
"@typeonce/ritmo": "^0.8.0"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=20"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser's monotonic clock as a core `HostClock`.
|
|
3
|
+
*
|
|
4
|
+
* `window.performance.now()` never goes backwards, unlike `Date.now`
|
|
5
|
+
* (`HostClock.standard`). The window is passed in, so nothing reads a global.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const runtime = Game.Runtime.make({ services, debug: { hostClock: BrowserHostClock.make(window) } })
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @module BrowserHostClock
|
|
13
|
+
*/
|
|
14
|
+
import type { HostClock } from "@typeonce/ritmo"
|
|
15
|
+
|
|
16
|
+
/** What the clock needs from the window. */
|
|
17
|
+
export interface Host {
|
|
18
|
+
readonly performance: { readonly now: () => number }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A host clock reading `host.performance.now()`. */
|
|
22
|
+
export const make = (host: Host): HostClock.HostClock => ({ now: () => host.performance.now() })
|
package/src/FixedLoop.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @module FixedLoop
|
|
9
9
|
* @docGroup browser
|
|
10
10
|
*/
|
|
11
|
+
import type * as Clock from "@typeonce/ritmo/Clock"
|
|
11
12
|
import * as Result from "@typeonce/ritmo/Result"
|
|
12
13
|
|
|
13
14
|
/** One renderer or browser tick measured in milliseconds. */
|
|
@@ -27,8 +28,11 @@ export interface TickSource<TTick extends Tick = Tick> {
|
|
|
27
28
|
|
|
28
29
|
/** Validated fixed-step timing policy. */
|
|
29
30
|
export interface Options {
|
|
30
|
-
/**
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The fixed step every update advances (`Clock.hz(60)`): the same value
|
|
33
|
+
* the game's clock resource runs at, so the loop and the clock agree.
|
|
34
|
+
*/
|
|
35
|
+
readonly step: Clock.Step
|
|
32
36
|
/** Maximum host-frame duration admitted into the accumulator. */
|
|
33
37
|
readonly maxFrameSeconds: number
|
|
34
38
|
/** Maximum number of simulation updates performed for one host frame. */
|
|
@@ -86,7 +90,7 @@ export const source = <TTick extends Tick>(
|
|
|
86
90
|
): TickSource<TTick> => ({ subscribe })
|
|
87
91
|
|
|
88
92
|
const validate = (options: Options): Result.Result<void, InvalidOptions> => {
|
|
89
|
-
for (const field of ["
|
|
93
|
+
for (const field of ["maxFrameSeconds"] as const) {
|
|
90
94
|
const value = options[field]
|
|
91
95
|
if (!Number.isFinite(value) || value <= 0) {
|
|
92
96
|
return Result.failure({
|
|
@@ -155,18 +159,18 @@ export const start = <TTick extends Tick, UpdateError>(
|
|
|
155
159
|
accumulator += elapsedSeconds
|
|
156
160
|
|
|
157
161
|
let fixedSteps = 0
|
|
158
|
-
while (accumulator >= options.
|
|
159
|
-
const update = options.update(options.
|
|
162
|
+
while (accumulator >= options.step.dt && fixedSteps < options.maxStepsPerFrame) {
|
|
163
|
+
const update = options.update(options.step.dt)
|
|
160
164
|
if (!update.ok) {
|
|
161
165
|
fail({ kind: "UpdateFailure", error: update.error })
|
|
162
166
|
return
|
|
163
167
|
}
|
|
164
|
-
accumulator -= options.
|
|
168
|
+
accumulator -= options.step.dt
|
|
165
169
|
fixedSteps += 1
|
|
166
170
|
}
|
|
167
171
|
|
|
168
|
-
if (accumulator >= options.
|
|
169
|
-
const droppedWholeSteps = Math.floor(accumulator / options.
|
|
172
|
+
if (accumulator >= options.step.dt) {
|
|
173
|
+
const droppedWholeSteps = Math.floor(accumulator / options.step.dt) * options.step.dt
|
|
170
174
|
accumulator -= droppedWholeSteps
|
|
171
175
|
droppedSeconds += droppedWholeSteps
|
|
172
176
|
}
|
|
@@ -174,7 +178,7 @@ export const start = <TTick extends Tick, UpdateError>(
|
|
|
174
178
|
options.render({
|
|
175
179
|
elapsedSeconds,
|
|
176
180
|
fixedSteps,
|
|
177
|
-
alpha: accumulator / options.
|
|
181
|
+
alpha: accumulator / options.step.dt,
|
|
178
182
|
droppedSeconds
|
|
179
183
|
})
|
|
180
184
|
}
|
package/src/InputCapture.ts
CHANGED
|
@@ -76,7 +76,7 @@ export interface Options<
|
|
|
76
76
|
* The generated system. It requires the source service and the resource.
|
|
77
77
|
*/
|
|
78
78
|
export type CaptureSystem<S extends Schema.Any, Root, Needs extends ServiceDescriptor | ResourceDescriptor | ConditionNeedsFromConditions<ReadonlyArray<Condition>>> =
|
|
79
|
-
Schema.BoundSystem<S, Root, any,
|
|
79
|
+
Schema.BoundSystem<S, Root, any, never, string, Needs>
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
82
|
* Builds the system that writes `source.snapshot()` into `resource`.
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Browser host integrations kept outside the renderer-agnostic ECS core. */
|
|
2
|
+
export * as BrowserHostClock from "./BrowserHostClock.ts"
|
|
2
3
|
export * as FixedLoop from "./FixedLoop.ts"
|
|
3
4
|
export * as InputCapture from "./InputCapture.ts"
|
|
4
5
|
export * as Keyboard from "./Keyboard.ts"
|