@driftengine/script 3.61.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.
Files changed (61) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/README.md +81 -0
  4. package/dist/bindings/ai.d.ts +66 -0
  5. package/dist/bindings/ai.js +173 -0
  6. package/dist/bindings/animation.d.ts +13 -0
  7. package/dist/bindings/animation.js +177 -0
  8. package/dist/bindings/audio.d.ts +56 -0
  9. package/dist/bindings/audio.js +126 -0
  10. package/dist/bindings/behavior.d.ts +36 -0
  11. package/dist/bindings/behavior.js +101 -0
  12. package/dist/bindings/chemistry.d.ts +72 -0
  13. package/dist/bindings/chemistry.js +253 -0
  14. package/dist/bindings/core.d.ts +172 -0
  15. package/dist/bindings/core.js +814 -0
  16. package/dist/bindings/editor.d.ts +53 -0
  17. package/dist/bindings/editor.js +248 -0
  18. package/dist/bindings/entities.d.ts +73 -0
  19. package/dist/bindings/entities.js +339 -0
  20. package/dist/bindings/interface.d.ts +55 -0
  21. package/dist/bindings/interface.js +200 -0
  22. package/dist/bindings/navigation.d.ts +36 -0
  23. package/dist/bindings/navigation.js +255 -0
  24. package/dist/bindings/network.d.ts +51 -0
  25. package/dist/bindings/network.js +96 -0
  26. package/dist/bindings/render.d.ts +71 -0
  27. package/dist/bindings/render.js +143 -0
  28. package/dist/bindings/rollback.d.ts +41 -0
  29. package/dist/bindings/rollback.js +74 -0
  30. package/dist/bindings/sprites.d.ts +53 -0
  31. package/dist/bindings/sprites.js +186 -0
  32. package/dist/bindings/terrain.d.ts +54 -0
  33. package/dist/bindings/terrain.js +138 -0
  34. package/dist/bindings/xr.d.ts +56 -0
  35. package/dist/bindings/xr.js +155 -0
  36. package/dist/entityHost.d.ts +80 -0
  37. package/dist/entityHost.js +159 -0
  38. package/dist/host.d.ts +153 -0
  39. package/dist/host.js +233 -0
  40. package/dist/index.d.ts +21 -0
  41. package/dist/index.js +18 -0
  42. package/package.json +68 -0
  43. package/src/bindings/ai.ts +306 -0
  44. package/src/bindings/animation.ts +346 -0
  45. package/src/bindings/audio.ts +185 -0
  46. package/src/bindings/behavior.ts +181 -0
  47. package/src/bindings/chemistry.ts +548 -0
  48. package/src/bindings/core.ts +1604 -0
  49. package/src/bindings/editor.ts +393 -0
  50. package/src/bindings/entities.ts +550 -0
  51. package/src/bindings/interface.ts +300 -0
  52. package/src/bindings/navigation.ts +367 -0
  53. package/src/bindings/network.ts +178 -0
  54. package/src/bindings/render.ts +191 -0
  55. package/src/bindings/rollback.ts +110 -0
  56. package/src/bindings/sprites.ts +310 -0
  57. package/src/bindings/terrain.ts +180 -0
  58. package/src/bindings/xr.ts +272 -0
  59. package/src/entityHost.ts +219 -0
  60. package/src/host.ts +465 -0
  61. package/src/index.ts +41 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * `drift/chemistry` — Track P's surface, and the thirteenth `drift/*` module.
3
+ *
4
+ * Like every binding here, nothing in it is new engine code: a binding is a **description and a
5
+ * lookup**. Where the surface needed a quantity `@driftengine/chemistry` did not have — a moisture
6
+ * content on a dry basis, a heat release rate, a char depth — that function was grown in the package
7
+ * that owns the subsystem and this describes it, per the rule in `host.ts`.
8
+ *
9
+ * ---
10
+ *
11
+ * ## Parcels are `i32`, and that is `drift/physics`'s convention followed rather than improved on
12
+ *
13
+ * A body is an `i32` there, a negative value means none, and a script author who has learned one
14
+ * surface has learned this one. A second convention for the same shape of thing is the kind of
15
+ * inconsistency nobody can defend a year later. `§20.2`.
16
+ *
17
+ * ## `chemistry.write` is inside the determinism boundary
18
+ *
19
+ * `capability.ts` wrote the rule that decides it and this track is the one entitled to apply it: a
20
+ * parcel's composition and enthalpy are simulated quantities in exactly the sense a component's
21
+ * fields are. They integrate on the fixed step and touch no clock. A rule that refused
22
+ * `chemistry.write` to a `@deterministic` function would refuse the canonical operation of the
23
+ * package.
24
+ *
25
+ * ## Two capabilities the design lists are **not** here, and neither is an oversight
26
+ *
27
+ * - **`wake`.** `§14`'s sleeping, budgets and LOD tiers were the design's CH-6 and were displaced
28
+ * when the build re-scoped that phase onto the temperature reading the ignition criteria had to
29
+ * read. Nothing sleeps, so a capability to wake it would be a no-op wearing a name — which is the
30
+ * rule against silent no-ops, arriving through a binding. It goes in with `§14`.
31
+ * - **`setAmbient`.** The ambient is the far field every live chunk was filled from and every vented
32
+ * kilogram was booked against. Changing it mid-run would leave the field holding air drawn from an
33
+ * atmosphere that no longer exists and the conservation ledger measuring against a moved baseline —
34
+ * which would make `elementTotals`, the single most valuable assertion in the track, meaningless.
35
+ * A consumer who wants a different atmosphere constructs the field with one. **Reversal:**
36
+ * re-baselining every live chunk and re-booking the ledger, which is a feature rather than a
37
+ * setter.
38
+ */
39
+ import { AtmosphereField, ChemistryWorld, ParcelStore, SpeciesRegistry, SubstanceRegistry, } from '@driftengine/chemistry';
40
+ import { defineComponent } from '@driftengine/entities';
41
+ import { defineCapability } from 'driftscript';
42
+ export const CHEMISTRY_MODULE = 'drift/chemistry';
43
+ const define = (name, params, returns, effects, doc) => defineCapability({
44
+ module: CHEMISTRY_MODULE,
45
+ name,
46
+ signature: `fn(${params.map((p) => `${p.name}: ${p.type}`).join(', ')}) -> ${returns}`,
47
+ params: [...params],
48
+ returns,
49
+ effects,
50
+ /* Every capability in this module is deterministic — see the header. */
51
+ deterministic: true,
52
+ doc,
53
+ implementation: `${CHEMISTRY_MODULE}.${name}`,
54
+ });
55
+ /**
56
+ * The three opaque types `§20.2` names.
57
+ *
58
+ * `Chemistry` is the world as `PhysicsWorld` is one. A `Substance` and a `Species` are registrations,
59
+ * and a script holds them to pass back rather than to read into — a field on either would be a
60
+ * promise about a representation the engine could then never change.
61
+ */
62
+ export const CHEMISTRY_TYPES = [
63
+ {
64
+ module: CHEMISTRY_MODULE,
65
+ name: 'Chemistry',
66
+ doc: 'A chemistry world: parcels, the air, and the tick that runs them.',
67
+ },
68
+ {
69
+ module: CHEMISTRY_MODULE,
70
+ name: 'Substance',
71
+ doc: 'A registered material: what it is made of and what it can turn into.',
72
+ },
73
+ {
74
+ module: CHEMISTRY_MODULE,
75
+ name: 'Species',
76
+ doc: 'A registered chemical species, such as `O2` or `cellulose`.',
77
+ },
78
+ ];
79
+ const READ = ['chemistry.read'];
80
+ const WRITE = ['chemistry.write'];
81
+ const P = { name: 'chem', type: 'Chemistry' };
82
+ const PARCEL = { name: 'parcel', type: 'i32' };
83
+ const XYZ = [
84
+ { name: 'x', type: 'f32' },
85
+ { name: 'y', type: 'f32' },
86
+ { name: 'z', type: 'f32' },
87
+ ];
88
+ export const CHEMISTRY_CAPABILITIES = [
89
+ /* Registration lookups: the two opaque handles enter a script here and nowhere else. */
90
+ define('substance', [P, { name: 'id', type: 'String' }], 'Substance', READ, 'A registered material by id, such as `oak`. Refuses in words naming what the world has.'),
91
+ define('species', [P, { name: 'id', type: 'String' }], 'Species', READ, 'A registered species by id, such as `O2`. Refuses in words if the world has no such species.'),
92
+ /* The read surface, §20.3. */
93
+ define('parcelCount', [P], 'i32', READ, 'How many parcel handles have ever been issued, live or not.'),
94
+ define('parcelAt', [P, { name: 'index', type: 'i32' }], 'i32', READ, 'The handle at an index, for iteration. Check `alive` before reading it.'),
95
+ define('alive', [P, PARCEL], 'bool', READ, 'Whether a parcel still exists.'),
96
+ define('substanceOf', [P, PARCEL], 'Substance', READ, 'What material a parcel is made of.'),
97
+ define('temperature', [P, PARCEL], 'f32', READ, 'K, averaged over the whole parcel.'),
98
+ define('surfaceTemperature', [P, PARCEL], 'f32', READ, 'K at the outermost shell — the one that decides whether it catches.'),
99
+ define('coreTemperature', [P, PARCEL], 'f32', READ, 'K at the innermost shell — the one that decides whether it is cooked.'),
100
+ define('mass', [P, PARCEL], 'f32', READ, 'How much of it there is, in kilograms. Falls as it burns.'),
101
+ define('speciesMass', [P, PARCEL, { name: 'species', type: 'Species' }], 'f32', READ, 'kg of one species held anywhere in this parcel.'),
102
+ define('moisture', [P, PARCEL], 'f32', READ, 'kg of water per kg of dry matter — the dry basis, which is how moisture content is quoted. Under 0.25 will burn; over 0.35 will not.'),
103
+ define('charFraction', [P, PARCEL], 'f32', READ, 'Share of the parcel that is now carbon, 0 to 1.'),
104
+ define('charDepth', [P, PARCEL], 'f32', READ, 'Metres of char measured inward from the surface.'),
105
+ define('wetness', [P, PARCEL], 'f32', READ, 'kg of liquid water on the surface, per square metre of it.'),
106
+ define('phase', [P, PARCEL], 'i32', READ, '0 solid, 1 liquid, 2 gas, 3 mixed. Mixed is a real answer: wet wood is a solid and a liquid at once.'),
107
+ define('burning', [P, PARCEL], 'bool', READ, 'Whether a flame stands over it.'),
108
+ define('smouldering', [P, PARCEL], 'bool', READ, 'Whether it is glowing with no flame. A smoulder survives air a flame cannot, which is why smothering leaves embers.'),
109
+ define('heatRelease', [P, PARCEL], 'f32', READ, "kW the reactions released last tick. A fire's size is its heat release rate, not its temperature. Negative while a surface is gasifying, which is correct."),
110
+ define('ignitionProgress', [P, PARCEL], 'f32', READ, 'How close to catching, 0 to 1: the least satisfied of the five criteria. A readout — nothing branches on it.'),
111
+ define('structuralIntegrity', [P, PARCEL], 'f32', READ, 'How much is still load-bearing, 1 down to 0, as char eats the thickness. This package breaks nothing; it reports.'),
112
+ define('massFlux', [P, PARCEL], 'f32', READ, 'kg/(m²·s) of gas leaving the surface — the smoke.'),
113
+ define('fuelFlux', [P, PARCEL], 'f32', READ, 'The combustible share of that, which is what ignition is measured against.'),
114
+ define('positionX', [P, PARCEL], 'f32', READ, 'Where the consumer said this parcel is.'),
115
+ define('positionY', [P, PARCEL], 'f32', READ, 'Where the consumer said this parcel is.'),
116
+ define('positionZ', [P, PARCEL], 'f32', READ, 'Where the consumer said this parcel is.'),
117
+ /* The air, sampled at a point. */
118
+ define('ambientTemperature', [P, ...XYZ], 'f32', READ, 'K of the air at a point.'),
119
+ define('oxygenFraction', [P, ...XYZ], 'f32', READ, 'Volume fraction of oxygen. Air is 0.209; a flame stops near 0.14 and a smoulder near 0.05.'),
120
+ define('humidity', [P, ...XYZ], 'f32', READ, 'Relative humidity, 0 to 1. Nothing dries in fog because the vapour pressure deficit is zero.'),
121
+ define('pressure', [P, ...XYZ], 'f32', READ, 'Pascals. Rises where the air is heated and confined, which is what an explosion event reports on.'),
122
+ define('concentration', [P, { name: 'species', type: 'Species' }, ...XYZ], 'f32', READ, 'Parts per million by volume. The reading a game acts on — carbon monoxide is the one that kills.'),
123
+ define('smokeDensity', [P, ...XYZ], 'f32', READ, 'Extinction coefficient, 1/m: what to attenuate a light along a ray by.'),
124
+ define('visibility', [P, ...XYZ], 'f32', READ, 'How far you can see, metres. Clamped at ten kilometres.'),
125
+ /* The write surface, §20.4. */
126
+ /*
127
+ * **`place`, not `spawn`, and `release`, not `emit`.** `§20.4` named both after words this
128
+ * language already reserves as statement heads — `spawn` starts a task and `emit` starts an event
129
+ * — so `chemistry.spawn(…)` does not parse at all. Renaming the capability is the narrow fix;
130
+ * making either a soft keyword would loosen the grammar everywhere for two names. The store's own
131
+ * method is still `spawn`, because TypeScript has no such collision.
132
+ */
133
+ define('place', [
134
+ P,
135
+ { name: 'substance', type: 'Substance' },
136
+ { name: 'kilograms', type: 'f32' },
137
+ { name: 'area', type: 'f32' },
138
+ ...XYZ,
139
+ ], 'i32', WRITE, 'Put a new parcel in the world. `area` is the exposed surface in m², and it is required rather than defaulted: a characteristic depth is volume over area, so a parcel with no area has no depth.'),
140
+ define('destroy', [P, PARCEL], 'void', WRITE, 'Remove a parcel. Its handle is never reused.'),
141
+ define('move', [P, PARCEL, ...XYZ], 'void', WRITE, 'Where it is. The consumer owns position; this package only reads it to work out what reaches it.'),
142
+ define('addHeat', [P, PARCEL, { name: 'joules', type: 'f32' }], 'void', WRITE, 'Joules into the surface shell, which is what a flux from outside does.'),
143
+ define('addHeatDeep', [P, PARCEL, { name: 'shell', type: 'i32' }, { name: 'joules', type: 'f32' }], 'void', WRITE, 'Joules into a named shell. The difference from `addHeat` is a microwave and an oven.'),
144
+ define('setTemperature', [P, PARCEL, { name: 'kelvin', type: 'f32' }], 'void', WRITE, 'Set every shell to a temperature. **For authoring and tests, not for a tick** — it discards whatever enthalpy was there rather than accounting for it.'),
145
+ define('wet', [P, PARCEL, { name: 'kilograms', type: 'f32' }], 'void', WRITE, 'Pour water on it: real liquid water into the surface shell, where boiling will find it. Refuses, naming the material, where that material holds no water.'),
146
+ define('dry', [P, PARCEL, { name: 'kilograms', type: 'f32' }], 'void', WRITE, 'Take surface water away: a cloth, a hot dry pan, or wind.'),
147
+ define('ignite', [P, PARCEL], 'void', WRITE, 'Supply a pilot for one tick. **This does not start a fire** — it satisfies one of five criteria, so holding a match to wet wood does nothing.'),
148
+ define('douse', [P, PARCEL], 'void', WRITE, 'Remove the pilot and the flame. Embers survive, which is the point of it.'),
149
+ define('addSpecies', [P, PARCEL, { name: 'species', type: 'Species' }, { name: 'kilograms', type: 'f32' }], 'void', WRITE, 'Salt the water, oil the pan, poison the well.'),
150
+ define('mix', [P, { name: 'from', type: 'i32' }, { name: 'into', type: 'i32' }], 'void', WRITE, 'Pour one parcel into another; the first is consumed. Both must be the same material — a mixture of two is a third material, authored as one.'),
151
+ define('release', [P, { name: 'species', type: 'Species' }, { name: 'kilograms', type: 'f32' }, ...XYZ], 'void', WRITE, 'A gas release into the air: a leak, a vent, an extinguisher.'),
152
+ define('addAirHeat', [P, { name: 'joules', type: 'f32' }, ...XYZ], 'void', WRITE, 'Joules into a cell of air, which is what a heater does and what a fire does to the room.'),
153
+ /* The event buffer, §20.5, in the shape `drift/physics`'s contact buffer established. */
154
+ define('eventCount', [P], 'i32', READ, 'Events this tick. Cleared at the top of every one.'),
155
+ define('eventKind', [P, { name: 'index', type: 'i32' }], 'i32', READ, '0 ignited, 1 extinguished, 2 smoulderStart, 3 smoulderEnd, 4 consumed, 5 charred, 6 structuralFail, 7 frozen, 8 melted, 9 boiled, 10 condensed, 11 sublimed, 12 corroded, 13 calcined, 14 dissolved, 15 denatured, 16 browned, 17 caramelised, 18 fermented, 19 decayed, 20 exploded.'),
156
+ define('eventParcel', [P, { name: 'index', type: 'i32' }], 'i32', READ, 'Which parcel it happened to.'),
157
+ define('eventSpecies', [P, { name: 'index', type: 'i32' }], 'i32', READ, 'Which species, or -1 where the kind does not name one.'),
158
+ define('eventValue', [P, { name: 'index', type: 'i32' }], 'f32', READ, "The kind's own quantity."),
159
+ ];
160
+ /**
161
+ * A parcel handle on an entity, and `§19` says why it is declared here.
162
+ *
163
+ * Track M's design is explicit that `@driftengine/entities` declares **no components** — it is the
164
+ * model, not a library of them. And `@driftengine/chemistry` imports no engine package at all, so it
165
+ * cannot declare one either. This binding layer is the one place that already depends on core,
166
+ * entities and now chemistry at once, which makes it the only honest home.
167
+ *
168
+ * `standoff` is not a chemistry quantity and is here because it is the one a consumer always ends up
169
+ * adding: how far this was placed from the fire, which is what `1/r²` is measured over.
170
+ */
171
+ export const CHEMISTRY_COMPONENT = defineComponent('Chemistry', {
172
+ parcel: 'i32',
173
+ standoff: 'f32',
174
+ });
175
+ export function chemistryImplementation(services) {
176
+ const { world, parcels, air, substances, species } = services;
177
+ /**
178
+ * Resolve an id, or refuse naming what the world has.
179
+ *
180
+ * **Not `-1` and not a no-op**, for the reason `drift/ecs` gives about a component name: a script
181
+ * that misspells `oak` would otherwise spawn nothing and read zeroes, which is a behaviour that
182
+ * runs, reports success and is wrong.
183
+ */
184
+ const substanceOf = (id) => {
185
+ const index = substances.indexOf(id);
186
+ if (index >= 0)
187
+ return index;
188
+ throw new Error(`no substance is registered as \`${id}\`. Install the library that carries it — ` +
189
+ '`@driftengine/chemistry/library/organic` has `oak`, `pine`, `paper`, `cotton`, `leather` ' +
190
+ 'and `straw` — or define one.');
191
+ };
192
+ const speciesOf = (id) => {
193
+ const index = species.indexOf(id);
194
+ if (index >= 0)
195
+ return index;
196
+ throw new Error(`no species is registered as \`${id}\`. The standard table has sixty-eight.`);
197
+ };
198
+ return {
199
+ substance: (_, id) => substanceOf(id),
200
+ species: (_, id) => speciesOf(id),
201
+ parcelCount: () => parcels.count,
202
+ parcelAt: (_, index) => index,
203
+ alive: (_, parcel) => parcels.alive(parcel),
204
+ substanceOf: (_, parcel) => parcels.substanceOf(parcel),
205
+ temperature: (_, parcel) => parcels.temperatureOf(parcel),
206
+ surfaceTemperature: (_, parcel) => parcels.surfaceTemperatureOf(parcel),
207
+ coreTemperature: (_, parcel) => parcels.coreTemperatureOf(parcel),
208
+ mass: (_, parcel) => parcels.massOf(parcel),
209
+ speciesMass: (_, parcel, s) => parcels.parcelSpeciesMass(parcel, s),
210
+ moisture: (_, parcel) => parcels.moistureOf(parcel),
211
+ charFraction: (_, parcel) => parcels.charFractionOf(parcel),
212
+ charDepth: (_, parcel) => parcels.charDepthOf(parcel),
213
+ wetness: (_, parcel) => parcels.wetnessOf(parcel),
214
+ phase: (_, parcel) => parcels.parcelPhaseOf(parcel),
215
+ burning: (_, parcel) => parcels.burning(parcel),
216
+ smouldering: (_, parcel) => parcels.smouldering(parcel),
217
+ /* Watts inside, kilowatts out: a fire is quoted in kW everywhere a person reads one. */
218
+ heatRelease: (_, parcel) => parcels.heatReleaseOf(parcel) / 1000,
219
+ ignitionProgress: (_, parcel) => world.ignitionProgressOf(parcel),
220
+ structuralIntegrity: (_, parcel) => parcels.structuralIntegrityOf(parcel),
221
+ massFlux: (_, parcel) => parcels.massFluxOf(parcel),
222
+ fuelFlux: (_, parcel) => parcels.fuelFluxOf(parcel),
223
+ positionX: (_, parcel) => parcels.positionX(parcel),
224
+ positionY: (_, parcel) => parcels.positionY(parcel),
225
+ positionZ: (_, parcel) => parcels.positionZ(parcel),
226
+ ambientTemperature: (_, x, y, z) => air.temperatureAt(x, y, z),
227
+ oxygenFraction: (_, x, y, z) => air.oxygenFractionAt(x, y, z),
228
+ humidity: (_, x, y, z) => air.humidityAt(x, y, z),
229
+ pressure: (_, x, y, z) => air.pressureAt(x, y, z),
230
+ concentration: (_, s, x, y, z) => air.concentrationAt(x, y, z, s),
231
+ smokeDensity: (_, x, y, z) => air.smokeDensityAt(x, y, z),
232
+ visibility: (_, x, y, z) => air.visibilityAt(x, y, z),
233
+ place: (_, substance, kilograms, area, x, y, z) => parcels.spawn({ substance, mass: kilograms, temperature: 293.15, area, x, y, z }),
234
+ destroy: (_, parcel) => parcels.destroy(parcel),
235
+ move: (_, parcel, x, y, z) => parcels.move(parcel, x, y, z),
236
+ addHeat: (_, parcel, joules) => parcels.addSurfaceHeat(parcel, joules),
237
+ addHeatDeep: (_, parcel, shell, joules) => parcels.addShellHeat(parcel, shell, joules),
238
+ setTemperature: (_, parcel, kelvin) => parcels.setTemperature(parcel, kelvin),
239
+ wet: (_, parcel, kilograms) => parcels.wet(parcel, kilograms),
240
+ dry: (_, parcel, kilograms) => parcels.dry(parcel, kilograms),
241
+ ignite: (_, parcel) => parcels.ignite(parcel),
242
+ douse: (_, parcel) => parcels.douse(parcel),
243
+ addSpecies: (_, parcel, s, kilograms) => parcels.addSpeciesMass(parcel, 0, s, kilograms),
244
+ mix: (_, from, into) => parcels.mix(from, into),
245
+ release: (_, s, kilograms, x, y, z) => air.addSpecies(x, y, z, s, kilograms),
246
+ addAirHeat: (_, joules, x, y, z) => air.addHeat(x, y, z, joules),
247
+ eventCount: () => world.events.count,
248
+ eventKind: (_, index) => world.events.kindOf(index),
249
+ eventParcel: (_, index) => world.events.parcelOf(index),
250
+ eventSpecies: (_, index) => world.events.speciesOf(index),
251
+ eventValue: (_, index) => world.events.valueOf(index),
252
+ };
253
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * The wired `drift/*` surfaces other than audio, in one file because each is a table.
3
+ *
4
+ * A binding is a **description plus a lookup**. Nothing here is new engine code, and if a binding
5
+ * needed the engine to grow a function, that function would belong in the package owning the
6
+ * subsystem and this would then describe it like any other.
7
+ *
8
+ * **What is deliberately absent, and why**, because an empty module is a decision rather than an
9
+ * oversight:
10
+ *
11
+ * - **`drift/core`.** §11 gives its provider as `startLoop` and `LoopHooks`. A script does not call
12
+ * those — they are what *drives* a script. There is nothing for a script to call, so the module
13
+ * is not registered rather than registered empty, and a target does not claim it.
14
+ * - **`drift/xr`.** No provider: Track I is the one track nobody has taken, and the linker refuses
15
+ * the module by name. **Twelve names stood in this list beside it and every one of them has since
16
+ * been bound** — `render`, `ui`, `2d`, `terrain`, `ecs`, `prefab`, `navigation`, `behavior`,
17
+ * `network`, `rollback`, `editor` and `ai` — and this sentence went on calling them unprovided,
18
+ * because a comment listing what is missing has no guard on it and goes stale in the one
19
+ * direction nothing checks.
20
+ */
21
+ import { ActionMap, type KeyValueStore, MessageQueue, type QueuedMessage } from '@driftengine/core';
22
+ import { type CapabilityDefinition, type OpaqueType } from 'driftscript';
23
+ export declare const TIME_MODULE = "drift/time";
24
+ export declare const RANDOM_MODULE = "drift/random";
25
+ export declare const EVENTS_MODULE = "drift/events";
26
+ export declare const PERSISTENCE_MODULE = "drift/persistence";
27
+ export declare const SCENE_MODULE = "drift/scene";
28
+ export declare const PHYSICS_MODULE = "drift/physics";
29
+ export declare const INPUT_MODULE = "drift/input";
30
+ export declare const CAMERA_MODULE = "drift/camera";
31
+ /**
32
+ * Handles a script holds and passes back, never reads into.
33
+ *
34
+ * A field on any of these would be a promise about a representation the engine could then never
35
+ * change — the design's safe-handle rule. `Node` is the one a script touches most, and it is still
36
+ * opaque: a position is read through a capability rather than off the object.
37
+ */
38
+ export declare const CORE_TYPES: readonly OpaqueType[];
39
+ /**
40
+ * `drift/time` — the loop's three clocks, and the one that is deterministic is not here.
41
+ *
42
+ * All three carry `clock.read`, so **none may be called from a `@deterministic` function** — and
43
+ * that is right even for the fixed step. A simulation is *given* its delta as a parameter; a
44
+ * simulation that reached out and read one has stopped being a function of its inputs, which is
45
+ * what replay depends on.
46
+ */
47
+ export declare const TIME_CAPABILITIES: readonly CapabilityDefinition[];
48
+ /**
49
+ * `drift/random` — a seeded generator whose sequence is **frozen**.
50
+ *
51
+ * Deterministic by construction, so a `@deterministic` function may call it. That is the whole
52
+ * reason it is a capability rather than a `std/*` function: the sequence is a promise about *this
53
+ * engine's* stored replays, and a standard library that shipped its own would either break that
54
+ * promise or silently become the thing that defines it.
55
+ */
56
+ export declare const RANDOM_CAPABILITIES: readonly CapabilityDefinition[];
57
+ /** `drift/events` — the engine's priority queue, with dedupe over a window and a backlog ceiling. */
58
+ export declare const EVENTS_CAPABILITIES: readonly CapabilityDefinition[];
59
+ /** `drift/persistence` — the store the consumer supplied, which may be a browser, a server or nothing. */
60
+ export declare const PERSISTENCE_CAPABILITIES: readonly CapabilityDefinition[];
61
+ /**
62
+ * `drift/scene` — the transform hierarchy from Phase 1.1.
63
+ *
64
+ * Reads are deterministic and writes are not, which is the boundary drawn per capability rather
65
+ * than per module. A simulation may ask where something is; moving it is a change to the world.
66
+ */
67
+ export declare const SCENE_CAPABILITIES: readonly CapabilityDefinition[];
68
+ /**
69
+ * `drift/physics` — bodies, contacts, queries and forces. **Not joints, not the controller and not
70
+ * ragdolls**, which is what this line said until 2026-08-27 and what none of the thirty-six
71
+ * capabilities below has ever done.
72
+ *
73
+ * **This module was two read-only functions until 2026-08-26**, and its own comment said why: there
74
+ * was no solver to write into, and a capability that pretended otherwise would have been the mock
75
+ * the design refused. Track B built the solver, so the surface is real — but the sentence that
76
+ * announced it was written from the *track's* deliverables rather than from this list, which is the
77
+ * same failure as a binding written from memory of what a camera ought to have. A reader looking
78
+ * for `joint` here found a comment that promised one.
79
+ *
80
+ * **Six of the thirty-six are `nearestWithin` and its accessors, added 2026-08-28**, and they exist
81
+ * because a consumer reported that `anyWithin` answers *whether* and never *what*. A script could
82
+ * already find the nearest entity — `drift/ecs` grew `findNearest` and `nearest` for that — and
83
+ * could not find the nearest wall, so what is in reach of a character was decided in TypeScript.
84
+ *
85
+ * **The two `within` questions measure different volumes, and the names cannot say so on their
86
+ * own.** `anyWithin` tests the axis-aligned *box* around the sphere, because that is what the
87
+ * collider hash indexes and testing anything narrower would cost a pass it does not need for a
88
+ * yes-or-no. `nearestWithin` is already walking each candidate to rank it, so it measures the
89
+ * sphere exactly and answers false where `anyWithin` answers true — a collider that reaches only
90
+ * the box corners. Both say which they do, on themselves, because a reader comparing the two names
91
+ * would have no reason to suspect it.
92
+ *
93
+ * **It measures to a collider's bounds rather than to the shape inside them**, which is the one
94
+ * place this surface is coarser than the sweep beside it. `ColliderSet`'s own header draws that
95
+ * line: the bounds are the broad phase and the shape resolves a contact, so a proximity answer that
96
+ * ran the convex sweep per candidate per frame would be paying contact prices for a distance. The
97
+ * documentation on each accessor says bounds, so nobody reads a banked slab's box as its surface.
98
+ *
99
+ * **What is missing, and the design question that is why it is still missing**: `JointDesc` carries
100
+ * twenty optional fields, so a script-side constructor is either an enormous signature or a builder
101
+ * this language has no shape for. That is a decision somebody has to take deliberately, and taking
102
+ * it badly would put a wrong-by-construction surface in front of every script author. Recorded here
103
+ * rather than guessed at.
104
+ *
105
+ * **Two parameters are required here that TypeScript leaves optional**, which is step four of the
106
+ * note at the top of `host.ts`, and both are the same shape of trap — an omission that produces a
107
+ * *wrong result* rather than an error:
108
+ *
109
+ * - **A raycast's layer mask.** Omitted, the first thing a ray finds is very often the body it
110
+ * started inside, because `raycastWorld` reports that body at fraction zero deliberately. A
111
+ * TypeScript caller has the context to know when that matters; a script author meets it first and
112
+ * reads it as the engine seeing through walls.
113
+ * - **An impulse's application point.** Omitted, the impulse goes through the centre of mass and
114
+ * produces no rotation whatever. Nothing throws; a crate simply slides instead of tumbling, which
115
+ * reads as a broken impulse rather than as a missing argument.
116
+ *
117
+ * **Every body and event index is `i32`, not `u32`.** `hitBody` has to be able to answer −1, and a
118
+ * script has no cast, so a mixed surface would make the obvious code — raycast, check the body,
119
+ * apply an impulse to it — impossible to write. One signed type throughout costs nothing and is
120
+ * what a query result already is.
121
+ *
122
+ * **A raycast's result is read back through separate accessors**, in the same shape `input.axisX`
123
+ * and `input.axisY` already use for a vector. A script has no way to receive an engine record, and
124
+ * inventing a flattened signature would drift from the real one the first time a hit gains a field —
125
+ * which is the reasoning `drift/camera` gives for leaving `cut` out. *What it costs* is that a hit
126
+ * is only valid until the next `raycast` on the same world, and the documentation says so on every
127
+ * accessor.
128
+ */
129
+ export declare const PHYSICS_CAPABILITIES: readonly CapabilityDefinition[];
130
+ /** `drift/input` — Track H, complete: action maps, rebinding, gamepad, pointer and touch. */
131
+ export declare const INPUT_CAPABILITIES: readonly CapabilityDefinition[];
132
+ /**
133
+ * `drift/camera` — the cinematic cameras, and **only what they actually have**.
134
+ *
135
+ * The first version of this binding described `lookAt` and `setPosition`. `CinematicCamera` has
136
+ * neither: it has `cut`, `snap`, `shotAgeSec` and `update`. The implementation reached them through
137
+ * an optional-call cast, so a script calling `camera.lookAt(…)` compiled, linked, ran, and did
138
+ * **nothing** — the silent no-op this repository's rules forbid, arriving by way of a binding
139
+ * written from memory of what a camera ought to have rather than from the class.
140
+ *
141
+ * `cut` is deliberately still absent: it takes a `ShotParams`, and a script has no way to construct
142
+ * an engine record yet. Binding it would mean inventing a flattened signature that drifts from the
143
+ * real one the first time a shot gains a field. It waits for a way to express the record.
144
+ */
145
+ export declare const CAMERA_CAPABILITIES: readonly CapabilityDefinition[];
146
+ /** What a host must supply for each module it wants to provide. */
147
+ export interface CoreServices {
148
+ readonly clocks?: {
149
+ fixedDelta(): number;
150
+ frameDelta(): number;
151
+ wallDelta(): number;
152
+ elapsed(): number;
153
+ };
154
+ readonly store?: KeyValueStore;
155
+ readonly queue?: MessageQueue<QueuedMessage>;
156
+ readonly actions?: ActionMap;
157
+ }
158
+ export declare function timeImplementation(clocks: NonNullable<CoreServices['clocks']>): Record<string, unknown>;
159
+ /**
160
+ * The seeded generator, dispatching to core's frozen sequence.
161
+ *
162
+ * `index` returns 0 for an empty collection rather than an error, because "pick from nothing" has
163
+ * one sane answer and a script asking is usually mid-way through a list that will have items next
164
+ * frame.
165
+ */
166
+ export declare function randomImplementation(): Record<string, unknown>;
167
+ export declare function eventsImplementation(): Record<string, unknown>;
168
+ export declare function persistenceImplementation(): Record<string, unknown>;
169
+ export declare function sceneImplementation(): Record<string, unknown>;
170
+ export declare function physicsImplementation(): Record<string, unknown>;
171
+ export declare function inputImplementation(): Record<string, unknown>;
172
+ export declare function cameraImplementation(): Record<string, unknown>;