koota-kit 0.3.1 → 0.5.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/CHANGELOG.md +15 -0
- package/README.md +43 -1
- package/dist/cjs/index.cjs +3 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/index.d.cts.map +1 -1
- package/dist/cjs/react.cjs +39 -0
- package/dist/cjs/react.d.cts +21 -0
- package/dist/cjs/react.d.cts.map +1 -0
- package/dist/cjs/rng.cjs +29 -0
- package/dist/cjs/rng.d.cts +13 -0
- package/dist/cjs/rng.d.cts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/react.d.ts +21 -0
- package/dist/esm/react.d.ts.map +1 -0
- package/dist/esm/react.js +34 -0
- package/dist/esm/rng.d.ts +13 -0
- package/dist/esm/rng.d.ts.map +1 -1
- package/dist/esm/rng.js +27 -0
- package/docs/API.md +35 -3
- package/docs/ARCHITECTURE.md +13 -1
- package/package.json +30 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0](https://github.com/jbcom/koota-kit/compare/v0.4.0...v0.5.0) (2026-10-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **react:** add koota-kit/react with SimWorldProvider and useSimWorld ([3a9aeee](https://github.com/jbcom/koota-kit/commit/3a9aeee17d67af90bb8be925fd123bfba32f2968))
|
|
9
|
+
* **react:** add koota-kit/react with SimWorldProvider and useSimWorld ([74a5f1c](https://github.com/jbcom/koota-kit/commit/74a5f1c683246797dfa60010375a3a4f6333d37c))
|
|
10
|
+
|
|
11
|
+
## [0.4.0](https://github.com/jbcom/koota-kit/compare/v0.3.1...v0.4.0) (2026-10-08)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **rng:** pick and shuffle over a stream ([167eb1c](https://github.com/jbcom/koota-kit/commit/167eb1c75fdb7aa2b78f9d9d4e2533c81e0b5230))
|
|
17
|
+
|
|
3
18
|
## [0.3.1](https://github.com/jbcom/koota-kit/compare/v0.3.0...v0.3.1) (2026-10-07)
|
|
4
19
|
|
|
5
20
|
|
package/README.md
CHANGED
|
@@ -38,6 +38,8 @@ Requirements:
|
|
|
38
38
|
The package declares `>=22`; support follows maintained Node lines rather
|
|
39
39
|
than requiring one exact patch release.
|
|
40
40
|
- Koota `^0.6.6`, installed by the application as a peer dependency
|
|
41
|
+
- React `>=18`, only if you import `koota-kit/react`; it is an optional peer
|
|
42
|
+
dependency, and no other entry point loads it
|
|
41
43
|
|
|
42
44
|
The package ships native ESM and CommonJS entry points with format-correct
|
|
43
45
|
TypeScript declarations.
|
|
@@ -154,9 +156,48 @@ and restores atomically.
|
|
|
154
156
|
Persist a version beside the header and your ECS state so the application can
|
|
155
157
|
migrate its own schema.
|
|
156
158
|
|
|
159
|
+
## React
|
|
160
|
+
|
|
161
|
+
`koota/react` hooks reach only the Koota `World`. `koota-kit/react` adds a
|
|
162
|
+
provider for the whole `WorldHandle`, so components can also reach its RNG
|
|
163
|
+
streams, seeds, clock and scratch:
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import { useQuery } from "koota/react";
|
|
167
|
+
import { createSimWorld, defineTrait, nextInt } from "koota-kit";
|
|
168
|
+
import { SimWorldProvider, useSimWorld } from "koota-kit/react";
|
|
169
|
+
|
|
170
|
+
const Position = defineTrait({ x: 0, y: 0 });
|
|
171
|
+
const handle = createSimWorld({ gen: "world-7", events: "run-7" });
|
|
172
|
+
|
|
173
|
+
function Scouts() {
|
|
174
|
+
const { rng } = useSimWorld(); // the handle: rng, seeds, clock, scratch
|
|
175
|
+
const scouts = useQuery(Position); // koota/react hooks share the same provider
|
|
176
|
+
return (
|
|
177
|
+
<button type="button" onClick={() => nextInt(rng.events, 1, 7)}>
|
|
178
|
+
Roll for {scouts.length} scouts
|
|
179
|
+
</button>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
root.render(
|
|
184
|
+
<SimWorldProvider handle={handle}>
|
|
185
|
+
<Scouts />
|
|
186
|
+
</SimWorldProvider>,
|
|
187
|
+
);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`SimWorldProvider` renders Koota's own `WorldProvider` for `handle.world`, so
|
|
191
|
+
`useTrait`, `useQuery` and `useActions` need no second provider. `useSimWorld()`
|
|
192
|
+
throws outside a provider. Passing a different `handle` re-provides every
|
|
193
|
+
consumer; the provider does not create or destroy the handle, so pair
|
|
194
|
+
`createSimWorld` with `destroySimWorld` yourself.
|
|
195
|
+
|
|
157
196
|
## API and architecture
|
|
158
197
|
|
|
159
|
-
The root package exports the full API
|
|
198
|
+
The root package exports the full API except the React bindings, which live
|
|
199
|
+
only at `koota-kit/react` so the root never loads React. Focused entry points
|
|
200
|
+
are also available:
|
|
160
201
|
|
|
161
202
|
| Entry point | Purpose |
|
|
162
203
|
| --- | --- |
|
|
@@ -165,6 +206,7 @@ The root package exports the full API. Focused entry points are also available:
|
|
|
165
206
|
| `koota-kit/seed` | Seed derivation and 128-bit master seeds |
|
|
166
207
|
| `koota-kit/traits` | Safe trait declaration |
|
|
167
208
|
| `koota-kit/eventLog` | World-scoped publish/drain logs |
|
|
209
|
+
| `koota-kit/react` | `SimWorldProvider` and `useSimWorld` (optional React peer) |
|
|
168
210
|
|
|
169
211
|
See the [API reference](./docs/API.md) for signatures and validation behavior,
|
|
170
212
|
and [architecture notes](./docs/ARCHITECTURE.md) for module boundaries and
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// ./eventLog — scratch-backed publish/drain event logs with a peek seam for
|
|
13
13
|
// observers (harnesses, tests, HUDs)
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.defineTrait = exports.defineEventLog = exports.MASTER_SEED_BYTES = exports.isMasterSeed = exports.deriveSeed = exports.createMasterSeed = exports.substream = exports.snapshotSubstreams = exports.snapshotStream = exports.snapshotLayers = exports.restoreSubstreams = exports.restoreStream = exports.restoreLayers = exports.nextU32 = exports.nextInt = exports.nextFloat = exports.getSubstream = exports.createSubstreams = exports.createRng = exports.chance = exports.trait = exports.snapshotWorld = exports.restoreWorldHeader = exports.relation = exports.destroySimWorld = exports.createSimWorld = exports.createActions = exports.advanceClock = void 0;
|
|
15
|
+
exports.defineTrait = exports.defineEventLog = exports.MASTER_SEED_BYTES = exports.isMasterSeed = exports.deriveSeed = exports.createMasterSeed = exports.substream = exports.snapshotSubstreams = exports.snapshotStream = exports.snapshotLayers = exports.shuffle = exports.restoreSubstreams = exports.restoreStream = exports.restoreLayers = exports.pick = exports.nextU32 = exports.nextInt = exports.nextFloat = exports.getSubstream = exports.createSubstreams = exports.createRng = exports.chance = exports.trait = exports.snapshotWorld = exports.restoreWorldHeader = exports.relation = exports.destroySimWorld = exports.createSimWorld = exports.createActions = exports.advanceClock = void 0;
|
|
16
16
|
var world_js_1 = require("./world.cjs");
|
|
17
17
|
Object.defineProperty(exports, "advanceClock", { enumerable: true, get: function () { return world_js_1.advanceClock; } });
|
|
18
18
|
Object.defineProperty(exports, "createActions", { enumerable: true, get: function () { return world_js_1.createActions; } });
|
|
@@ -30,9 +30,11 @@ Object.defineProperty(exports, "getSubstream", { enumerable: true, get: function
|
|
|
30
30
|
Object.defineProperty(exports, "nextFloat", { enumerable: true, get: function () { return rng_js_1.nextFloat; } });
|
|
31
31
|
Object.defineProperty(exports, "nextInt", { enumerable: true, get: function () { return rng_js_1.nextInt; } });
|
|
32
32
|
Object.defineProperty(exports, "nextU32", { enumerable: true, get: function () { return rng_js_1.nextU32; } });
|
|
33
|
+
Object.defineProperty(exports, "pick", { enumerable: true, get: function () { return rng_js_1.pick; } });
|
|
33
34
|
Object.defineProperty(exports, "restoreLayers", { enumerable: true, get: function () { return rng_js_1.restoreLayers; } });
|
|
34
35
|
Object.defineProperty(exports, "restoreStream", { enumerable: true, get: function () { return rng_js_1.restoreStream; } });
|
|
35
36
|
Object.defineProperty(exports, "restoreSubstreams", { enumerable: true, get: function () { return rng_js_1.restoreSubstreams; } });
|
|
37
|
+
Object.defineProperty(exports, "shuffle", { enumerable: true, get: function () { return rng_js_1.shuffle; } });
|
|
36
38
|
Object.defineProperty(exports, "snapshotLayers", { enumerable: true, get: function () { return rng_js_1.snapshotLayers; } });
|
|
37
39
|
Object.defineProperty(exports, "snapshotStream", { enumerable: true, get: function () { return rng_js_1.snapshotStream; } });
|
|
38
40
|
Object.defineProperty(exports, "snapshotSubstreams", { enumerable: true, get: function () { return rng_js_1.snapshotSubstreams; } });
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { advanceClock, createActions, createSimWorld, destroySimWorld, relation, restoreWorldHeader, snapshotWorld, trait, } from "./world.cjs";
|
|
2
2
|
export type { Entity, World, WorldHandle, WorldSnapshot } from "./world.cjs";
|
|
3
|
-
export { chance, createRng, createSubstreams, getSubstream, nextFloat, nextInt, nextU32, restoreLayers, restoreStream, restoreSubstreams, snapshotLayers, snapshotStream, snapshotSubstreams, substream, } from "./rng.cjs";
|
|
3
|
+
export { chance, createRng, createSubstreams, getSubstream, nextFloat, nextInt, nextU32, pick, restoreLayers, restoreStream, restoreSubstreams, shuffle, snapshotLayers, snapshotStream, snapshotSubstreams, substream, } from "./rng.cjs";
|
|
4
4
|
export type { RngLayers, RngLayersSnapshot, RngSeeds, RngStream, RngStreamSnapshot, Substreams, SubstreamsSnapshot, } from "./rng.cjs";
|
|
5
5
|
export { createMasterSeed, deriveSeed, isMasterSeed, MASTER_SEED_BYTES } from "./seed.cjs";
|
|
6
6
|
export type { EntropySource, SeedPart } from "./seed.cjs";
|
package/dist/cjs/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,IAAI,EACJ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// React bindings for the sim handle. This is the ONLY module that imports
|
|
3
|
+
// React (through koota/react), and nothing else in the package imports it, so
|
|
4
|
+
// the root entry and every other subpath stay React-free. `react` is an
|
|
5
|
+
// optional peer dependency: consumers who never import `koota-kit/react` never
|
|
6
|
+
// need it installed.
|
|
7
|
+
//
|
|
8
|
+
// koota/react's own `WorldProvider` / `useWorld` carry only the koota `World`.
|
|
9
|
+
// A component that needs the handle's RNG streams, seeds, clock or scratch
|
|
10
|
+
// cannot reach them from there. `SimWorldProvider` supplies the whole
|
|
11
|
+
// `WorldHandle` AND mounts koota's provider for `handle.world`, so
|
|
12
|
+
// `useTrait`, `useQuery` and `useActions` work underneath it unchanged.
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.SimWorldProvider = void 0;
|
|
15
|
+
exports.useSimWorld = useSimWorld;
|
|
16
|
+
const react_1 = require("koota/react");
|
|
17
|
+
const react_2 = require("react");
|
|
18
|
+
const SimWorldContext = (0, react_2.createContext)(null);
|
|
19
|
+
SimWorldContext.displayName = "SimWorldContext";
|
|
20
|
+
/**
|
|
21
|
+
* Provide a `WorldHandle` to the tree below. Renders koota's `WorldProvider`
|
|
22
|
+
* for `handle.world`, so every `koota/react` hook works under it without a
|
|
23
|
+
* second provider. The provider does not own the handle's lifecycle: create it
|
|
24
|
+
* with `createSimWorld` and release it with `destroySimWorld` yourself.
|
|
25
|
+
*/
|
|
26
|
+
const SimWorldProvider = ({ handle, children }) => (0, react_2.createElement)(SimWorldContext.Provider, { value: handle }, (0, react_2.createElement)(react_1.WorldProvider, { world: handle.world, children }));
|
|
27
|
+
exports.SimWorldProvider = SimWorldProvider;
|
|
28
|
+
/**
|
|
29
|
+
* The `WorldHandle` provided by the nearest `SimWorldProvider`: its `world`,
|
|
30
|
+
* `rng`, `seeds`, `clock` and `scratch`. Throws when called outside one — a
|
|
31
|
+
* missing provider is a wiring bug, not a state to render around.
|
|
32
|
+
*/
|
|
33
|
+
function useSimWorld() {
|
|
34
|
+
const handle = (0, react_2.useContext)(SimWorldContext);
|
|
35
|
+
if (handle === null) {
|
|
36
|
+
throw new Error("useSimWorld must be used within a <SimWorldProvider>");
|
|
37
|
+
}
|
|
38
|
+
return handle;
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FunctionComponent, ReactNode } from "react";
|
|
2
|
+
import type { WorldHandle } from "./world.cjs";
|
|
3
|
+
export type SimWorldProviderProps = {
|
|
4
|
+
/** The handle from `createSimWorld`. Swapping it re-provides every consumer. */
|
|
5
|
+
readonly handle: WorldHandle;
|
|
6
|
+
readonly children?: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Provide a `WorldHandle` to the tree below. Renders koota's `WorldProvider`
|
|
10
|
+
* for `handle.world`, so every `koota/react` hook works under it without a
|
|
11
|
+
* second provider. The provider does not own the handle's lifecycle: create it
|
|
12
|
+
* with `createSimWorld` and release it with `destroySimWorld` yourself.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SimWorldProvider: FunctionComponent<SimWorldProviderProps>;
|
|
15
|
+
/**
|
|
16
|
+
* The `WorldHandle` provided by the nearest `SimWorldProvider`: its `world`,
|
|
17
|
+
* `rng`, `seeds`, `clock` and `scratch`. Throws when called outside one — a
|
|
18
|
+
* missing provider is a wiring bug, not a state to render around.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useSimWorld(): WorldHandle;
|
|
21
|
+
//# sourceMappingURL=react.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/react.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B,CAAC;AAKF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,CAAC,qBAAqB,CAKnE,CAAC;AAEJ;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,WAAW,CAMzC"}
|
package/dist/cjs/rng.cjs
CHANGED
|
@@ -28,6 +28,8 @@ exports.nextU32 = nextU32;
|
|
|
28
28
|
exports.nextFloat = nextFloat;
|
|
29
29
|
exports.nextInt = nextInt;
|
|
30
30
|
exports.chance = chance;
|
|
31
|
+
exports.pick = pick;
|
|
32
|
+
exports.shuffle = shuffle;
|
|
31
33
|
exports.snapshotStream = snapshotStream;
|
|
32
34
|
exports.snapshotLayers = snapshotLayers;
|
|
33
35
|
exports.restoreStream = restoreStream;
|
|
@@ -118,6 +120,33 @@ function chance(stream, p) {
|
|
|
118
120
|
}
|
|
119
121
|
return nextFloat(stream) < p;
|
|
120
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Pick one element of `items` uniformly. Valid calls consume exactly one
|
|
125
|
+
* `nextInt` draw; an empty array is rejected without consuming the stream,
|
|
126
|
+
* so a caller can never silently skip a draw it meant to make.
|
|
127
|
+
*/
|
|
128
|
+
function pick(stream, items) {
|
|
129
|
+
if (items.length === 0) {
|
|
130
|
+
throw new RangeError("pick: items must not be empty.");
|
|
131
|
+
}
|
|
132
|
+
return items[nextInt(stream, 0, items.length)];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Return a uniformly shuffled copy of `items` (Fisher–Yates, from the last
|
|
136
|
+
* index down). The input is never mutated. Valid calls consume exactly
|
|
137
|
+
* `items.length - 1` draws (none for zero or one element), so the draw count
|
|
138
|
+
* depends only on the length — replay stays aligned whatever the contents.
|
|
139
|
+
*/
|
|
140
|
+
function shuffle(stream, items) {
|
|
141
|
+
const out = [...items];
|
|
142
|
+
for (let i = out.length - 1; i > 0; i--) {
|
|
143
|
+
const j = nextInt(stream, 0, i + 1);
|
|
144
|
+
const swap = out[i];
|
|
145
|
+
out[i] = out[j];
|
|
146
|
+
out[j] = swap;
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
121
150
|
/**
|
|
122
151
|
* Capture `stream`'s internal seedrandom state as a plain, JSON-serializable
|
|
123
152
|
* object (deep-cloned, so later draws on `stream` cannot mutate the
|
package/dist/cjs/rng.d.cts
CHANGED
|
@@ -50,6 +50,19 @@ export declare function nextInt(stream: RngStream, minInclusive: number, maxExcl
|
|
|
50
50
|
* deterministic across codepaths that must replay identically.
|
|
51
51
|
*/
|
|
52
52
|
export declare function chance(stream: RngStream, p: number): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Pick one element of `items` uniformly. Valid calls consume exactly one
|
|
55
|
+
* `nextInt` draw; an empty array is rejected without consuming the stream,
|
|
56
|
+
* so a caller can never silently skip a draw it meant to make.
|
|
57
|
+
*/
|
|
58
|
+
export declare function pick<T>(stream: RngStream, items: readonly T[]): T;
|
|
59
|
+
/**
|
|
60
|
+
* Return a uniformly shuffled copy of `items` (Fisher–Yates, from the last
|
|
61
|
+
* index down). The input is never mutated. Valid calls consume exactly
|
|
62
|
+
* `items.length - 1` draws (none for zero or one element), so the draw count
|
|
63
|
+
* depends only on the length — replay stays aligned whatever the contents.
|
|
64
|
+
*/
|
|
65
|
+
export declare function shuffle<T>(stream: RngStream, items: readonly T[]): T[];
|
|
53
66
|
export type RngStreamSnapshot = {
|
|
54
67
|
state: State;
|
|
55
68
|
};
|
package/dist/cjs/rng.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rng.d.ts","sourceRoot":"","sources":["../../src/rng.ts"],"names":[],"mappings":"AAqBA,OAAO,UAAU,MAAM,YAAY,CAAC;AAGpC,KAAK,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;AACnC,KAAK,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AAE/C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC,CAAC;AAgBF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAUpD;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAc7F;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAK5D;AAED,MAAM,MAAM,iBAAiB,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEtF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,iBAAiB,CAGnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,iBAAiB,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAqBhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAKhE;AAUD,MAAM,MAAM,UAAU,GAAG;IACvB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC5C,CAAC;AAcF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAGxE;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAGlE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAO5E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,kBAAkB,CAW7E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,UAAU,CAiB1E"}
|
|
1
|
+
{"version":3,"file":"rng.d.ts","sourceRoot":"","sources":["../../src/rng.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { advanceClock, createActions, createSimWorld, destroySimWorld, relation, restoreWorldHeader, snapshotWorld, trait, } from "./world.js";
|
|
2
2
|
export type { Entity, World, WorldHandle, WorldSnapshot } from "./world.js";
|
|
3
|
-
export { chance, createRng, createSubstreams, getSubstream, nextFloat, nextInt, nextU32, restoreLayers, restoreStream, restoreSubstreams, snapshotLayers, snapshotStream, snapshotSubstreams, substream, } from "./rng.js";
|
|
3
|
+
export { chance, createRng, createSubstreams, getSubstream, nextFloat, nextInt, nextU32, pick, restoreLayers, restoreStream, restoreSubstreams, shuffle, snapshotLayers, snapshotStream, snapshotSubstreams, substream, } from "./rng.js";
|
|
4
4
|
export type { RngLayers, RngLayersSnapshot, RngSeeds, RngStream, RngStreamSnapshot, Substreams, SubstreamsSnapshot, } from "./rng.js";
|
|
5
5
|
export { createMasterSeed, deriveSeed, isMasterSeed, MASTER_SEED_BYTES } from "./seed.js";
|
|
6
6
|
export type { EntropySource, SeedPart } from "./seed.js";
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,IAAI,EACJ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// ./eventLog — scratch-backed publish/drain event logs with a peek seam for
|
|
12
12
|
// observers (harnesses, tests, HUDs)
|
|
13
13
|
export { advanceClock, createActions, createSimWorld, destroySimWorld, relation, restoreWorldHeader, snapshotWorld, trait, } from "./world.js";
|
|
14
|
-
export { chance, createRng, createSubstreams, getSubstream, nextFloat, nextInt, nextU32, restoreLayers, restoreStream, restoreSubstreams, snapshotLayers, snapshotStream, snapshotSubstreams, substream, } from "./rng.js";
|
|
14
|
+
export { chance, createRng, createSubstreams, getSubstream, nextFloat, nextInt, nextU32, pick, restoreLayers, restoreStream, restoreSubstreams, shuffle, snapshotLayers, snapshotStream, snapshotSubstreams, substream, } from "./rng.js";
|
|
15
15
|
export { createMasterSeed, deriveSeed, isMasterSeed, MASTER_SEED_BYTES } from "./seed.js";
|
|
16
16
|
export { defineEventLog } from "./eventLog.js";
|
|
17
17
|
export { defineTrait } from "./traits/index.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FunctionComponent, ReactNode } from "react";
|
|
2
|
+
import type { WorldHandle } from "./world.js";
|
|
3
|
+
export type SimWorldProviderProps = {
|
|
4
|
+
/** The handle from `createSimWorld`. Swapping it re-provides every consumer. */
|
|
5
|
+
readonly handle: WorldHandle;
|
|
6
|
+
readonly children?: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Provide a `WorldHandle` to the tree below. Renders koota's `WorldProvider`
|
|
10
|
+
* for `handle.world`, so every `koota/react` hook works under it without a
|
|
11
|
+
* second provider. The provider does not own the handle's lifecycle: create it
|
|
12
|
+
* with `createSimWorld` and release it with `destroySimWorld` yourself.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SimWorldProvider: FunctionComponent<SimWorldProviderProps>;
|
|
15
|
+
/**
|
|
16
|
+
* The `WorldHandle` provided by the nearest `SimWorldProvider`: its `world`,
|
|
17
|
+
* `rng`, `seeds`, `clock` and `scratch`. Throws when called outside one — a
|
|
18
|
+
* missing provider is a wiring bug, not a state to render around.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useSimWorld(): WorldHandle;
|
|
21
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/react.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B,CAAC;AAKF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,CAAC,qBAAqB,CAKnE,CAAC;AAEJ;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,WAAW,CAMzC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// React bindings for the sim handle. This is the ONLY module that imports
|
|
2
|
+
// React (through koota/react), and nothing else in the package imports it, so
|
|
3
|
+
// the root entry and every other subpath stay React-free. `react` is an
|
|
4
|
+
// optional peer dependency: consumers who never import `koota-kit/react` never
|
|
5
|
+
// need it installed.
|
|
6
|
+
//
|
|
7
|
+
// koota/react's own `WorldProvider` / `useWorld` carry only the koota `World`.
|
|
8
|
+
// A component that needs the handle's RNG streams, seeds, clock or scratch
|
|
9
|
+
// cannot reach them from there. `SimWorldProvider` supplies the whole
|
|
10
|
+
// `WorldHandle` AND mounts koota's provider for `handle.world`, so
|
|
11
|
+
// `useTrait`, `useQuery` and `useActions` work underneath it unchanged.
|
|
12
|
+
import { WorldProvider } from "koota/react";
|
|
13
|
+
import { createContext, createElement, useContext } from "react";
|
|
14
|
+
const SimWorldContext = createContext(null);
|
|
15
|
+
SimWorldContext.displayName = "SimWorldContext";
|
|
16
|
+
/**
|
|
17
|
+
* Provide a `WorldHandle` to the tree below. Renders koota's `WorldProvider`
|
|
18
|
+
* for `handle.world`, so every `koota/react` hook works under it without a
|
|
19
|
+
* second provider. The provider does not own the handle's lifecycle: create it
|
|
20
|
+
* with `createSimWorld` and release it with `destroySimWorld` yourself.
|
|
21
|
+
*/
|
|
22
|
+
export const SimWorldProvider = ({ handle, children }) => createElement(SimWorldContext.Provider, { value: handle }, createElement(WorldProvider, { world: handle.world, children }));
|
|
23
|
+
/**
|
|
24
|
+
* The `WorldHandle` provided by the nearest `SimWorldProvider`: its `world`,
|
|
25
|
+
* `rng`, `seeds`, `clock` and `scratch`. Throws when called outside one — a
|
|
26
|
+
* missing provider is a wiring bug, not a state to render around.
|
|
27
|
+
*/
|
|
28
|
+
export function useSimWorld() {
|
|
29
|
+
const handle = useContext(SimWorldContext);
|
|
30
|
+
if (handle === null) {
|
|
31
|
+
throw new Error("useSimWorld must be used within a <SimWorldProvider>");
|
|
32
|
+
}
|
|
33
|
+
return handle;
|
|
34
|
+
}
|
package/dist/esm/rng.d.ts
CHANGED
|
@@ -50,6 +50,19 @@ export declare function nextInt(stream: RngStream, minInclusive: number, maxExcl
|
|
|
50
50
|
* deterministic across codepaths that must replay identically.
|
|
51
51
|
*/
|
|
52
52
|
export declare function chance(stream: RngStream, p: number): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Pick one element of `items` uniformly. Valid calls consume exactly one
|
|
55
|
+
* `nextInt` draw; an empty array is rejected without consuming the stream,
|
|
56
|
+
* so a caller can never silently skip a draw it meant to make.
|
|
57
|
+
*/
|
|
58
|
+
export declare function pick<T>(stream: RngStream, items: readonly T[]): T;
|
|
59
|
+
/**
|
|
60
|
+
* Return a uniformly shuffled copy of `items` (Fisher–Yates, from the last
|
|
61
|
+
* index down). The input is never mutated. Valid calls consume exactly
|
|
62
|
+
* `items.length - 1` draws (none for zero or one element), so the draw count
|
|
63
|
+
* depends only on the length — replay stays aligned whatever the contents.
|
|
64
|
+
*/
|
|
65
|
+
export declare function shuffle<T>(stream: RngStream, items: readonly T[]): T[];
|
|
53
66
|
export type RngStreamSnapshot = {
|
|
54
67
|
state: State;
|
|
55
68
|
};
|
package/dist/esm/rng.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rng.d.ts","sourceRoot":"","sources":["../../src/rng.ts"],"names":[],"mappings":"AAqBA,OAAO,UAAU,MAAM,YAAY,CAAC;AAGpC,KAAK,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;AACnC,KAAK,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;AAE/C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC,CAAC;AAgBF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAUpD;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAc7F;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAK5D;AAED,MAAM,MAAM,iBAAiB,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEtF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,iBAAiB,CAGnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,iBAAiB,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAqBhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAKhE;AAUD,MAAM,MAAM,UAAU,GAAG;IACvB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC5C,CAAC;AAcF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAGxE;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAGlE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAO5E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,kBAAkB,CAW7E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,UAAU,CAiB1E"}
|
|
1
|
+
{"version":3,"file":"rng.d.ts","sourceRoot":"","sources":["../../src/rng.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/rng.js
CHANGED
|
@@ -99,6 +99,33 @@ export function chance(stream, p) {
|
|
|
99
99
|
}
|
|
100
100
|
return nextFloat(stream) < p;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Pick one element of `items` uniformly. Valid calls consume exactly one
|
|
104
|
+
* `nextInt` draw; an empty array is rejected without consuming the stream,
|
|
105
|
+
* so a caller can never silently skip a draw it meant to make.
|
|
106
|
+
*/
|
|
107
|
+
export function pick(stream, items) {
|
|
108
|
+
if (items.length === 0) {
|
|
109
|
+
throw new RangeError("pick: items must not be empty.");
|
|
110
|
+
}
|
|
111
|
+
return items[nextInt(stream, 0, items.length)];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Return a uniformly shuffled copy of `items` (Fisher–Yates, from the last
|
|
115
|
+
* index down). The input is never mutated. Valid calls consume exactly
|
|
116
|
+
* `items.length - 1` draws (none for zero or one element), so the draw count
|
|
117
|
+
* depends only on the length — replay stays aligned whatever the contents.
|
|
118
|
+
*/
|
|
119
|
+
export function shuffle(stream, items) {
|
|
120
|
+
const out = [...items];
|
|
121
|
+
for (let i = out.length - 1; i > 0; i--) {
|
|
122
|
+
const j = nextInt(stream, 0, i + 1);
|
|
123
|
+
const swap = out[i];
|
|
124
|
+
out[i] = out[j];
|
|
125
|
+
out[j] = swap;
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
102
129
|
/**
|
|
103
130
|
* Capture `stream`'s internal seedrandom state as a plain, JSON-serializable
|
|
104
131
|
* object (deep-cloned, so later draws on `stream` cannot mutate the
|
package/docs/API.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# API reference
|
|
2
2
|
|
|
3
|
-
All functions and types are exported from `koota-kit
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
All functions and types are exported from `koota-kit`, except the React
|
|
4
|
+
bindings, which are only available from `koota-kit/react` so the root entry
|
|
5
|
+
never loads React. The module-specific import paths shown below can reduce
|
|
6
|
+
coupling in larger codebases.
|
|
6
7
|
|
|
7
8
|
## `world`
|
|
8
9
|
|
|
@@ -68,6 +69,8 @@ function nextU32(stream: RngStream): number;
|
|
|
68
69
|
function nextFloat(stream: RngStream): number;
|
|
69
70
|
function nextInt(stream: RngStream, minInclusive: number, maxExclusive: number): number;
|
|
70
71
|
function chance(stream: RngStream, probability: number): boolean;
|
|
72
|
+
function pick<T>(stream: RngStream, items: readonly T[]): T;
|
|
73
|
+
function shuffle<T>(stream: RngStream, items: readonly T[]): T[];
|
|
71
74
|
function snapshotStream(stream: RngStream): RngStreamSnapshot;
|
|
72
75
|
function restoreStream(snapshot: RngStreamSnapshot): RngStream;
|
|
73
76
|
function snapshotLayers(layers: RngLayers): RngLayersSnapshot;
|
|
@@ -79,6 +82,11 @@ function restoreLayers(snapshot: RngLayersSnapshot): RngLayers;
|
|
|
79
82
|
- `nextInt` uses half-open bounds and exactly one float draw after validation.
|
|
80
83
|
- `chance` consumes one draw for every valid probability, including `0` and
|
|
81
84
|
`1`, keeping later draw positions predictable.
|
|
85
|
+
- `pick` returns one element uniformly with exactly one `nextInt` draw and
|
|
86
|
+
rejects an empty array without drawing.
|
|
87
|
+
- `shuffle` returns a Fisher–Yates shuffled copy (the input is never mutated)
|
|
88
|
+
and consumes exactly `length - 1` draws, so the draw count depends only on
|
|
89
|
+
the length, never on the contents.
|
|
82
90
|
- Restore functions reject malformed ARC4 state and clone accepted state so a
|
|
83
91
|
snapshot can seed multiple independent replays.
|
|
84
92
|
|
|
@@ -185,3 +193,27 @@ Logs are created once at module scope but store their arrays in each handle's
|
|
|
185
193
|
scratch map. `drain` truncates the live array in place so an existing internal
|
|
186
194
|
reference is not orphaned. Empty reads do not create a scratch entry. `peek`
|
|
187
195
|
returns a detached array; `size` does not allocate.
|
|
196
|
+
|
|
197
|
+
## `react`
|
|
198
|
+
|
|
199
|
+
Import from `koota-kit/react`. Requires `react` (`>=18`), an optional peer
|
|
200
|
+
dependency; no other entry point imports it.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
type SimWorldProviderProps = {
|
|
204
|
+
readonly handle: WorldHandle;
|
|
205
|
+
readonly children?: ReactNode;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const SimWorldProvider: FunctionComponent<SimWorldProviderProps>;
|
|
209
|
+
function useSimWorld(): WorldHandle;
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`SimWorldProvider` supplies `handle` to the tree below it and renders
|
|
213
|
+
`koota/react`'s `WorldProvider` for `handle.world`, so `useWorld`, `useTrait`,
|
|
214
|
+
`useQuery` and `useActions` work under it without a second provider.
|
|
215
|
+
`useSimWorld` returns the provided handle, including its `rng`, `seeds`,
|
|
216
|
+
`clock` and `scratch`, and throws an `Error` when no `SimWorldProvider` is above
|
|
217
|
+
it. Passing a different `handle` re-provides every consumer. The provider does
|
|
218
|
+
not create or destroy the handle: pair `createSimWorld` with `destroySimWorld`
|
|
219
|
+
yourself.
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -12,7 +12,8 @@ seed ─────────────────> (leaf: built-in SHA-25
|
|
|
12
12
|
rng ──────────────────> seedrandom + seed
|
|
13
13
|
world ────────────────> koota + rng
|
|
14
14
|
eventLog ─────────────> WorldHandle scratch
|
|
15
|
-
|
|
15
|
+
react ────────────────> koota/react + react + world (type only)
|
|
16
|
+
index ────────────────> public re-exports only (never react)
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
`traits` is a leaf module: it imports Koota but no sibling runtime module. This
|
|
@@ -36,6 +37,16 @@ not own application entity serialization.
|
|
|
36
37
|
`eventLog` uses the handle's scratch map so event lifetime matches world
|
|
37
38
|
lifetime. It does not use a process-global queue.
|
|
38
39
|
|
|
40
|
+
`react` is the only module that imports React, through `koota/react`. It is
|
|
41
|
+
reachable only from the `koota-kit/react` subpath: `index` does not re-export it,
|
|
42
|
+
and `react` is an optional peer dependency, so an application that never imports
|
|
43
|
+
that subpath never needs React installed. It carries the `WorldHandle` through a
|
|
44
|
+
context and mounts Koota's own `WorldProvider` for `handle.world`, which keeps
|
|
45
|
+
one source of truth for the world. It imports `world` for types only and owns no
|
|
46
|
+
lifecycle: creating and destroying the handle stays with the application.
|
|
47
|
+
`pnpm package:check` walks every other built entry's import graph and fails if
|
|
48
|
+
it reaches `react` or `koota/react`.
|
|
49
|
+
|
|
39
50
|
## Invariants
|
|
40
51
|
|
|
41
52
|
1. Seed values on a handle are copied and frozen at creation.
|
|
@@ -47,6 +58,7 @@ lifetime. It does not use a process-global queue.
|
|
|
47
58
|
7. World teardown clears facade-owned scratch state and releases the Koota ID.
|
|
48
59
|
8. A named substream's sequence depends only on its seed and name; creating or
|
|
49
60
|
consuming another substream never shifts it.
|
|
61
|
+
9. Only `koota-kit/react` imports React; every other entry stays React-free.
|
|
50
62
|
|
|
51
63
|
## Performance choices
|
|
52
64
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koota-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Deterministic Koota simulation conventions: world lifecycle, dual RNG streams, safe object traits, and world-scoped event logs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -73,6 +73,16 @@
|
|
|
73
73
|
"default": "./dist/cjs/eventLog.cjs"
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
|
+
"./react": {
|
|
77
|
+
"import": {
|
|
78
|
+
"types": "./dist/esm/react.d.ts",
|
|
79
|
+
"default": "./dist/esm/react.js"
|
|
80
|
+
},
|
|
81
|
+
"require": {
|
|
82
|
+
"types": "./dist/cjs/react.d.cts",
|
|
83
|
+
"default": "./dist/cjs/react.cjs"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
76
86
|
"./package.json": "./package.json"
|
|
77
87
|
},
|
|
78
88
|
"files": [
|
|
@@ -109,18 +119,33 @@
|
|
|
109
119
|
"seedrandom": "^3.0.5"
|
|
110
120
|
},
|
|
111
121
|
"peerDependencies": {
|
|
112
|
-
"
|
|
122
|
+
"@types/react": ">=18.0.0",
|
|
123
|
+
"koota": "^0.6.6",
|
|
124
|
+
"react": ">=18.0.0"
|
|
125
|
+
},
|
|
126
|
+
"peerDependenciesMeta": {
|
|
127
|
+
"@types/react": {
|
|
128
|
+
"optional": true
|
|
129
|
+
},
|
|
130
|
+
"react": {
|
|
131
|
+
"optional": true
|
|
132
|
+
}
|
|
113
133
|
},
|
|
114
134
|
"devDependencies": {
|
|
115
135
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
116
136
|
"@biomejs/biome": "^2.5.5",
|
|
117
137
|
"@commitlint/cli": "^21.2.2",
|
|
118
138
|
"@commitlint/config-conventional": "^21.2.2",
|
|
139
|
+
"@types/react": "^19.3.0",
|
|
140
|
+
"@types/react-dom": "^19.3.0",
|
|
119
141
|
"@vitest/coverage-v8": "^3.2.7",
|
|
142
|
+
"jsdom": "^30.1.2",
|
|
120
143
|
"koota": "^0.6.6",
|
|
121
144
|
"lint-staged": "^17.3.0",
|
|
122
145
|
"markdownlint-cli2": "^0.23.2",
|
|
123
146
|
"publint": "^0.3.24",
|
|
147
|
+
"react": "^19.3.0",
|
|
148
|
+
"react-dom": "^19.3.0",
|
|
124
149
|
"simple-git-hooks": "^2.13.1",
|
|
125
150
|
"typescript": "^5.9.2",
|
|
126
151
|
"vitest": "^3.2.4"
|
|
@@ -166,6 +191,9 @@
|
|
|
166
191
|
"eventLog": [
|
|
167
192
|
"./dist/esm/eventLog.d.ts"
|
|
168
193
|
],
|
|
194
|
+
"react": [
|
|
195
|
+
"./dist/esm/react.d.ts"
|
|
196
|
+
],
|
|
169
197
|
"*": [
|
|
170
198
|
"./dist/esm/index.d.ts"
|
|
171
199
|
]
|