@patterkit/runtime 0.12.1 → 0.14.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 +48 -0
- package/README.md +25 -6
- package/dist/index.cjs +275 -125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -27
- package/dist/index.d.ts +90 -27
- package/dist/index.js +272 -122
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -33,6 +33,54 @@ version number always means the same runtime behaviour. This package is versione
|
|
|
33
33
|
|
|
34
34
|
## [Unreleased]
|
|
35
35
|
|
|
36
|
+
## [0.14.0] - 2026-09-24
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **Other engines' scopes, with no setting.** A Patter line can name another engine's game-wide scope from the family's shared list (`@story.act` in a condition, an effect, or a `{@story.act}` slot) in any project. It is opaque to the compiler, recorded in the bundle (`externalScopes`), and never self-backed. Content that names one runs only where that engine is on the same registry: without it, `openFlow` and `loadGame` refuse before anything changes (`this content names @story, which no engine on this registry registered: give every engine the game's one registry`), and a write to a scope another engine has since removed fails naming the scope instead of landing in `@patter`.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **One registry per game.** Every property bag the engine holds now lives in a `ScopeRegistry`
|
|
45
|
+
(`@wildwinter/scoperegistry` 0.7.0): `@patter` under `patter`, and each flow's and scene's bag
|
|
46
|
+
under a key starting `patter/`. A new `registry` option takes the game's own registry, shared
|
|
47
|
+
with any other engine in the game; without one the engine makes its own and acts as its own game,
|
|
48
|
+
so a single-engine game needs no change.
|
|
49
|
+
- **The save is version 3.** `saveGame()` holds what is not a property (cursors, PRNGs, visit
|
|
50
|
+
counts, selector cursors). An engine built without a registry also carries that registry's values
|
|
51
|
+
under `registry`, so one call is still the whole game; an engine given the game's registry leaves
|
|
52
|
+
them to the game, which saves the registry once. Version 2 saves still load, their values moving
|
|
53
|
+
into the registry.
|
|
54
|
+
- **A self-backed `@world` is saved.** When the game binds no resolver, `@world` is a property the
|
|
55
|
+
engine's registry stores, so it rides in the save. A resolver the game binds is still external and
|
|
56
|
+
never saved. Given the game's registry, the engine self-backs nothing: `@world` is the game's to
|
|
57
|
+
register there.
|
|
58
|
+
- **Every expression reads every registered scope**, so a condition can test another engine's
|
|
59
|
+
`@story.act` in a combined game. A token two engines both want fails as the second is built, naming
|
|
60
|
+
the first.
|
|
61
|
+
- `hotSwap` hands every bag to the replacement engine on the same registry. The engine it replaces is
|
|
62
|
+
released and its flows are closed. If the restore fails, the fallback engine keeps the shared
|
|
63
|
+
properties and restarts each flow, where it used to start everything cold.
|
|
64
|
+
|
|
65
|
+
### Deprecated
|
|
66
|
+
|
|
67
|
+
- `Engine.save()` / `Engine.load()`, the shared `@patter` values alone. Save the registry instead.
|
|
68
|
+
|
|
69
|
+
## [0.13.0] - 2026-09-05
|
|
70
|
+
|
|
71
|
+
### Changed
|
|
72
|
+
|
|
73
|
+
- **A `writable: false` host declaration is the STORY's promise, and only the story's: the game
|
|
74
|
+
writes it.** `Engine.setProperty` / `Flow.setProperty` are the game's surfaces, so they now write a
|
|
75
|
+
read-only `@world` property whether it is self-backed or bound to a resolver; an effect that writes
|
|
76
|
+
one is refused exactly as before, with the same sentence. Until now the runtime refused every
|
|
77
|
+
caller alike, so a game could not advance its own clock through the engine and a Patterplay
|
|
78
|
+
coverage driver on such a property killed the run - which is how both this project and the
|
|
79
|
+
Storylet Engine found it, on the same day, in different content
|
|
80
|
+
(from-storylets/host-writes-to-read-only-world). The rule now lives in the shared kernel
|
|
81
|
+
(`@wildwinter/scoperegistry` ^0.6.0, an explicit host authority on `set`), so both products mean
|
|
82
|
+
the same thing by the flag.
|
|
83
|
+
|
|
36
84
|
## [0.12.1] - 2026-09-04
|
|
37
85
|
|
|
38
86
|
### Changed
|
package/README.md
CHANGED
|
@@ -40,9 +40,11 @@ for (;;) {
|
|
|
40
40
|
}
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
`new Engine(bundle, options)` takes `{ rng?, seed?, locale?, world?, replayPromptOnChoose?, closedCaptions? }`:
|
|
43
|
+
`new Engine(bundle, options)` takes `{ rng?, seed?, locale?, world?, registry?, replayPromptOnChoose?, closedCaptions? }`:
|
|
44
44
|
- `world` is the host's resolver for `@world` properties (World Properties): `{ get(name), set?(name, value) }`.
|
|
45
|
-
Omit it and the runtime self-backs `@world` from the declared defaults.
|
|
45
|
+
Omit it and the runtime self-backs `@world` from the declared defaults, as a property it saves.
|
|
46
|
+
- `registry` is the game's one `ScopeRegistry` (from `@wildwinter/scoperegistry`), holding every
|
|
47
|
+
engine's properties. Omit it and the engine makes its own. See *One registry per game* below.
|
|
46
48
|
- `locale` plays a non-default language (embedded localisation; an IDs-only bundle ignores it).
|
|
47
49
|
- A string the active locale is missing falls back to the default-locale source,
|
|
48
50
|
flagged `<Untranslated: {id}> {source}` so a partial translation is impossible to miss.
|
|
@@ -90,7 +92,24 @@ The release zip's `demos/` folder holds two working references (in the repo:
|
|
|
90
92
|
|
|
91
93
|
## Save / load
|
|
92
94
|
|
|
93
|
-
`engine.saveGame()` returns a JSON-serialisable snapshot of the whole game (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
`engine.saveGame()` returns a JSON-serialisable snapshot of the whole game (visit counts,
|
|
96
|
+
selector cursors, every live flow, and, for an engine built without a registry, every property
|
|
97
|
+
value); `engine.loadGame(blob)` restores it. Saves from before property values moved into the
|
|
98
|
+
registry (version 2) still load. [@patterkit/play-helpers](../play-helpers) wraps these as
|
|
99
|
+
`serializeState` / `deserializeState` with a tagged envelope.
|
|
100
|
+
|
|
101
|
+
## One registry per game
|
|
102
|
+
|
|
103
|
+
A game has one `ScopeRegistry` holding every property from every engine, except values the game
|
|
104
|
+
keeps itself and lends through a resolver, and saves it once. Pass it as `registry`:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { ScopeRegistry } from "@wildwinter/scoperegistry";
|
|
108
|
+
|
|
109
|
+
const registry = new ScopeRegistry().defineOwned("world", worldDeclarations, { owner: "Game" });
|
|
110
|
+
const engine = new Engine(bundle, { registry });
|
|
111
|
+
const save = { registry: registry.save(), patter: engine.saveGame() }; // saveGame() holds no values now
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The engine registers `@patter` under `patter` and every per-flow and per-scene bag under a key
|
|
115
|
+
starting `patter/`; `@world` is the game's to register. Loading works in either order.
|