@realitycollective/iwsdk-environment 0.1.0-preview.2 → 0.1.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 CHANGED
@@ -4,11 +4,12 @@ Change log for the Reality Collective WebXR Environment Extensions packages. All
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Preview builds are not listed separately. The entry for a version accumulates while its previews are published, and is dated when that version is released.
6
6
 
7
- ## [0.1.0]
7
+ ## [0.1.0] - 2026-09-17
8
8
 
9
9
  ### Added
10
10
 
11
11
  - `verify:pack` now lints the shape of what ships: publint over every package directory, with warnings counted as errors, and attw (Are The Types Wrong) over every packed tarball, resolving the published types under node10, node16 and bundler resolution. `cjs-resolves-to-esm` is ignored by design, because every package is ESM-only and a require() caller is expected to use a dynamic import. Both run offline on the tarballs the script already builds; `publint` and `@arethetypeswrong/cli` are dev dependencies. The script stays identical across the Reality Collective repositories.
12
+ - `verify:pack` now also type-checks the published declarations themselves, with library checking on, through `scripts/declaration-check.mjs`, runnable on its own as `node scripts/declaration-check.mjs`. Each package's declaration entry is compiled as a strict consumer would compile it, with `skipLibCheck: false`, under nodenext and then bundler resolution; a diagnostic inside the package fails the run, and diagnostics inside upstream declaration files are counted and ignored, because they are not ours to fix and would drown the signal. attw proves the published types resolve; this proves they compile, which is what a consumer with library checking on, or a package emitting declarations on top of ours, needs. The check is opt-in per repository, through `declarationCheck` in `scripts/release.config.json`, because only a foreign declaration can put a name into our emitted types that the build did not already check. This repository reaches around 950 of them, from the IWSDK and three.js typings the adapter is built against, and every run prints that count so the opt-in stays measured rather than habitual. It is the check that would have caught the bare `World` under Fixed.
12
13
  - `@realitycollective/webxr-environment` - the engine-free core. `EnvironmentDirector` holds a sky (gradient or solid), fog (linear or exponential), an ambient light and a key light as plain data; interpolates between named presets over a host-supplied `update(deltaMs)`; pushes only the slots that actually changed to an `EnvironmentPort`; and applies passthrough as a suppression over what the app asked for, so nothing has to remember what to restore. A partial `EnvironmentSpec` inherits the slots it omits and turns off the ones it sets to `null`, which is what makes presets composable. Six example presets (`void`, `dawn`, `noon`, `dusk`, `night`, `overcast`) to copy, and `clearedFog`, the helper that makes fog easeable in.
13
14
  - `@realitycollective/webxr-environment` - `AudioDirector`: a cue registry, a bus and master mix with mute kept separate from gain, per-cue retrigger policy (`overlap` / `restart` / `ignore`), a per-cue minimum retrigger interval, and voice tracking. The `AudioPort` is handed an absolute resolved gain and has no mixing left to do. A silent one-shot is never started; a silent loop is, so that unmuting mid-flight finds the ambience bed already running.
14
15
  - `@realitycollective/threejs-environment` - the three.js adapter. Gradient skies become an equirectangular `DataTexture` generated by a pure function and regenerated in place across a transition; `Fog` / `FogExp2` are mutated rather than rebuilt while the kind holds; the key light is positioned from the direction light travels. Audio runs over `Audio` / `PositionalAudio`, and a play that arrives before its buffer has decoded is held rather than dropped, so the first press of a session is not silent.
@@ -31,6 +32,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
31
32
 
32
33
  ### Fixed
33
34
 
35
+ - `@realitycollective/iwsdk-environment` emitted the same bare `World` in `EnvironmentSystem`'s base type that broke a consumer of the UI Extensions adapter on 9 September 2026. The cause is upstream: `@iwsdk/core` 0.5.3's `dist/ecs/system.d.ts` imports `World` from `'./world'` with no extension, the only such import in the package, and under the NodeNext resolution this repository builds with that import does not resolve (TS2835), so `World` was an unresolved name inside the host's own declaration and TypeScript's declaration emitter preserved it verbatim. `skipLibCheck` hid the error on both sides. It compiled for consumers only because `index.d.ts` happened to import `World` for another signature. The adapter now takes `createSystem` from its own `src/create-system.ts`, a wrapper whose return type names `World` through `@iwsdk/core`'s barrel, so the emitted base type no longer depends on that accident. The wrapper goes the day IWSDK ships `./world.js` there.
34
36
  - `@realitycollective/iwsdk-environment` imported three.js's `Vector3`, `Quaternion`, `Fog` and `FogExp2` through `@iwsdk/core`, which only provides them by `export * from 'three'`. That resolves in node and in every demo, and fails a consumer whose Vite config excludes `three` from dependency optimization, which any app that transforms three's source does: esbuild cannot enumerate a star re-export it is not bundling, and the dev server stops with `No matching export in "@iwsdk/core" for import "Vector3"`, a message that names neither the package nor the cause. The audio, environment and world-sensing ports now import those classes from `three`, declared as a peer dependency (`>=0.170.0`, the range the three.js adapter carries), which every IWSDK application already has. `@types/three` is pinned to `0.185.4` across the workspace (root `overrides`), the typings for the super-three 0.185 the workspace runs, so the tree holds one copy of the three typings rather than the two that made the adapter's tests import `Scene` through `@iwsdk/core`. The Anatomy Atlas XR client reported the failure against the UI Extensions adapter; the estate sweep found the same import here.
35
37
  - Two gates, shared with every Reality Collective repository. `packages/webxr-environment/test/import-surface.test.ts` runs `scripts/import-surface.mjs` over every published package and fails an import of a name that a dependency only re-exports from another package, and any bare import of a package the manifest does not declare. `packages/iwsdk-environment/test/prebundle.test.ts` runs the dependency optimizer of every bundler `scripts/release.config.json` names (`scripts/prebundle-check.mjs`) over the adapter next to `@iwsdk/core`, once with defaults and once with every package `@iwsdk/core` re-exports wholesale excluded, so the consumer path is exercised on every `npm test`. It runs on **Vite 7 and Vite 8**, because this fault belongs to a bundler rather than to bundling: Vite 7 optimizes with esbuild, which requires every named import to be statically enumerable and so rejects a name behind an external `export *`, while Vite 8 optimizes with rolldown, which resolves the same import lazily through a namespace object and accepts it. Testing only one of them would say nothing about consumers on the other. The versions under test are ordinary devDependencies installed under npm aliases, `vite-7` and `vite-8`, the same mechanism the workspace already uses for `three`; add an entry to `prebundle.bundlers` to support another. Each run also feeds the optimizer a **deliberately broken copy** of the adapter, carrying one extra module that imports a name the host only re-exports wholesale, and asserts the bundler's verdict matches that bundler's `detectsStarHops` flag. The probed name is discovered from the host's own surface rather than hard-coded, so it stays valid as that surface changes. This is what stops the check becoming decoration: on a permissive bundler a gate that can only pass reports safety it never verified, and the suite now fails if a bundler's strictness moves in either direction, or if no supported bundler can detect the fault at all. Transpiling uses the TypeScript compiler the repository already builds with, so no bundler is a hidden requirement of the harness itself. Both were red before this fix.
36
38
  - **A hand ray is now cast from the hand.** The three.js world-sensing port used to bind every hit test to the viewer's reference space and mention in a detail string that hands were not really supported, which meant the most common AR gesture - point at the floor, place something - silently aimed from the head. It now looks the input source up by handedness, binds to its `targetRaySpace`, waits visibly while there is no such source, and unbinds when the hand goes away.
@@ -47,4 +49,4 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
47
49
  - **A body solver was considered and declined.** No host exposes a body, so it fails the boundary test this repository is built on; see [`docs/BOUNDARY.md`](docs/BOUNDARY.md). Planes, meshes, anchors and hit test are real platform sensing but feed placement and interaction rather than the environment, and are recorded there as a separate component rather than as slots of `EnvironmentSpec`.
48
50
  - Every slot the environment describes is a PLATFORM facility each host exposes differently - `scene.background` and `Fog` on three.js, `DomeGradient` and `AmbientLightComponent` on IWSDK. CONTENT is the app's: no geometry is created by either adapter, and the stock presets are examples to copy rather than art direction. See [`docs/BOUNDARY.md`](docs/BOUNDARY.md) for the boundary in full, and [`docs/UPSTREAM_ENHANCEMENTS.md`](docs/UPSTREAM_ENHANCEMENTS.md) for the gaps that belong to the other packages rather than this one.
49
51
 
50
- [0.1.0]: https://github.com/realitycollective/WebXR-Environment/commits/main
52
+ [0.1.0]: https://github.com/realitycollective/WebXR-Environment/releases/tag/v0.1.0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `createSystem` from `@iwsdk/core`, with its return type written out.
3
+ *
4
+ * Why this file exists. IWSDK 0.5.3 declares `createSystem` in
5
+ * `dist/ecs/system.d.ts` as returning `SystemConstructor<S, Q, World, System<S, Q>>`,
6
+ * and that file imports `World` from './world' with no extension, the only
7
+ * extensionless relative import in the package. This repository builds with
8
+ * `moduleResolution: NodeNext`, under which an extensionless relative import
9
+ * in an ES module does not resolve (TS2835), so inside the host's own
10
+ * declaration `World` is an unresolved name. `skipLibCheck` hides the error,
11
+ * and TypeScript's declaration emitter preserves an unresolved name verbatim,
12
+ * so every `export class X extends createSystem(...)` in this package was
13
+ * emitted with a bare `World` in its base type. A consumer that checks
14
+ * library files (`skipLibCheck: false`, or a package emitting declarations on
15
+ * top of ours) fails with TS2304 on its first import of this package. A file
16
+ * that happened to import `World` for another signature resolved the bare
17
+ * name by accident, which is how the sibling adapters looked clean.
18
+ *
19
+ * The annotation below names `World` through `@iwsdk/core`'s barrel, whose
20
+ * imports all carry extensions, so the emitter writes
21
+ * `import("@iwsdk/core").World` wherever the result is extended. Every system
22
+ * in this package takes `createSystem` from here, never from `@iwsdk/core`.
23
+ * `elics` is imported for its types only: it is `@iwsdk/core`'s own
24
+ * dependency, the import is erased at build time, and the emitted
25
+ * declarations already name `import("elics").SystemConstructor`.
26
+ *
27
+ * Delete this file, and import `createSystem` from `@iwsdk/core` again, once
28
+ * IWSDK ships `./world.js` there. `scripts/declaration-check.mjs`, run by
29
+ * `verify:pack`, is the check that fails while the bare name is emitted.
30
+ */
31
+ import { type System, type World } from "@iwsdk/core";
32
+ import type { SystemConstructor, SystemQueries, SystemSchema } from "elics";
33
+ export declare function createSystem<S extends SystemSchema, Q extends SystemQueries>(queries?: Q, schema?: S): SystemConstructor<S, Q, World, System<S, Q>>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `createSystem` from `@iwsdk/core`, with its return type written out.
3
+ *
4
+ * Why this file exists. IWSDK 0.5.3 declares `createSystem` in
5
+ * `dist/ecs/system.d.ts` as returning `SystemConstructor<S, Q, World, System<S, Q>>`,
6
+ * and that file imports `World` from './world' with no extension, the only
7
+ * extensionless relative import in the package. This repository builds with
8
+ * `moduleResolution: NodeNext`, under which an extensionless relative import
9
+ * in an ES module does not resolve (TS2835), so inside the host's own
10
+ * declaration `World` is an unresolved name. `skipLibCheck` hides the error,
11
+ * and TypeScript's declaration emitter preserves an unresolved name verbatim,
12
+ * so every `export class X extends createSystem(...)` in this package was
13
+ * emitted with a bare `World` in its base type. A consumer that checks
14
+ * library files (`skipLibCheck: false`, or a package emitting declarations on
15
+ * top of ours) fails with TS2304 on its first import of this package. A file
16
+ * that happened to import `World` for another signature resolved the bare
17
+ * name by accident, which is how the sibling adapters looked clean.
18
+ *
19
+ * The annotation below names `World` through `@iwsdk/core`'s barrel, whose
20
+ * imports all carry extensions, so the emitter writes
21
+ * `import("@iwsdk/core").World` wherever the result is extended. Every system
22
+ * in this package takes `createSystem` from here, never from `@iwsdk/core`.
23
+ * `elics` is imported for its types only: it is `@iwsdk/core`'s own
24
+ * dependency, the import is erased at build time, and the emitted
25
+ * declarations already name `import("elics").SystemConstructor`.
26
+ *
27
+ * Delete this file, and import `createSystem` from `@iwsdk/core` again, once
28
+ * IWSDK ships `./world.js` there. `scripts/declaration-check.mjs`, run by
29
+ * `verify:pack`, is the check that fails while the bare name is emitted.
30
+ */
31
+ import { createSystem as createIWSDKSystem } from "@iwsdk/core";
32
+ export function createSystem(queries, schema) {
33
+ return createIWSDKSystem(queries, schema);
34
+ }
35
+ //# sourceMappingURL=create-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-system.js","sourceRoot":"","sources":["../src/create-system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,YAAY,IAAI,iBAAiB,EAA2B,MAAM,aAAa,CAAC;AAGzF,MAAM,UAAU,YAAY,CAC1B,OAAW,EACX,MAAU;IAEV,OAAO,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["/**\n * `createSystem` from `@iwsdk/core`, with its return type written out.\n *\n * Why this file exists. IWSDK 0.5.3 declares `createSystem` in\n * `dist/ecs/system.d.ts` as returning `SystemConstructor<S, Q, World, System<S, Q>>`,\n * and that file imports `World` from './world' with no extension, the only\n * extensionless relative import in the package. This repository builds with\n * `moduleResolution: NodeNext`, under which an extensionless relative import\n * in an ES module does not resolve (TS2835), so inside the host's own\n * declaration `World` is an unresolved name. `skipLibCheck` hides the error,\n * and TypeScript's declaration emitter preserves an unresolved name verbatim,\n * so every `export class X extends createSystem(...)` in this package was\n * emitted with a bare `World` in its base type. A consumer that checks\n * library files (`skipLibCheck: false`, or a package emitting declarations on\n * top of ours) fails with TS2304 on its first import of this package. A file\n * that happened to import `World` for another signature resolved the bare\n * name by accident, which is how the sibling adapters looked clean.\n *\n * The annotation below names `World` through `@iwsdk/core`'s barrel, whose\n * imports all carry extensions, so the emitter writes\n * `import(\"@iwsdk/core\").World` wherever the result is extended. Every system\n * in this package takes `createSystem` from here, never from `@iwsdk/core`.\n * `elics` is imported for its types only: it is `@iwsdk/core`'s own\n * dependency, the import is erased at build time, and the emitted\n * declarations already name `import(\"elics\").SystemConstructor`.\n *\n * Delete this file, and import `createSystem` from `@iwsdk/core` again, once\n * IWSDK ships `./world.js` there. `scripts/declaration-check.mjs`, run by\n * `verify:pack`, is the check that fails while the bare name is emitted.\n */\nimport { createSystem as createIWSDKSystem, type System, type World } from \"@iwsdk/core\";\nimport type { SystemConstructor, SystemQueries, SystemSchema } from \"elics\";\n\nexport function createSystem<S extends SystemSchema, Q extends SystemQueries>(\n queries?: Q,\n schema?: S,\n): SystemConstructor<S, Q, World, System<S, Q>> {\n return createIWSDKSystem(queries, schema);\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Re-exports the whole engine-free core, so an app installs this package and
5
5
  * nothing else.
6
6
  */
7
- import { type Entity, type World } from "@iwsdk/core";
7
+ import type { Entity, World } from "@iwsdk/core";
8
8
  import type { AudioDirectorOptions, EnvironmentDirectorOptions } from "@realitycollective/webxr-environment";
9
9
  import { AudioDirector, EnvironmentDirector } from "@realitycollective/webxr-environment";
10
10
  import type { IWSDKEnvironmentPortOptions } from "./environment-port.js";
package/dist/index.js CHANGED
@@ -1,10 +1,4 @@
1
- /**
2
- * `@realitycollective/iwsdk-environment` - the Meta IWSDK adapter.
3
- *
4
- * Re-exports the whole engine-free core, so an app installs this package and
5
- * nothing else.
6
- */
7
- import { createSystem } from "@iwsdk/core";
1
+ import { createSystem } from "./create-system.js";
8
2
  import { AudioDirector, EnvironmentDirector } from "@realitycollective/webxr-environment";
9
3
  import { IWSDKEnvironmentPort } from "./environment-port.js";
10
4
  import { IWSDKAudioPort } from "./audio-port.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAA2B,MAAM,aAAa,CAAC;AAKpE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,cAAc,sCAAsC,CAAC;AAkBrD,MAAM,KAAK,GAAG,IAAI,OAAO,EAAgC,CAAC;AAE1D,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,iBAAkB,SAAQ,YAAY,CAAC,EAAE,CAAC;IAC5C,MAAM,CAAC,KAAa;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAyB,CAAC,CAAC;QACxD,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAChC,MAAM,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;QAC7B,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAY,EACZ,UAAmC,EAAE;IAErC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAE5C,MAAM,eAAe,GAAG,IAAI,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IAEtE,IAAI,KAAK,GAAyB,IAAI,CAAC;IACvC,IAAI,SAAS,GAA0B,IAAI,CAAC;IAC5C,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,SAAS,GAAG,IAAI,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACrD,KAAK,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,KAAK,GAA0B;QACnC,WAAW;QACX,eAAe;QACf,KAAK;QACL,SAAS;QACT,OAAO;YACL,KAAK,EAAE,OAAO,EAAE,CAAC;YACjB,WAAW,CAAC,OAAO,EAAE,CAAC;YACtB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;KACF,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACxB,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * `@realitycollective/iwsdk-environment` - the Meta IWSDK adapter.\n *\n * Re-exports the whole engine-free core, so an app installs this package and\n * nothing else.\n */\nimport { createSystem, type Entity, type World } from \"@iwsdk/core\";\nimport type {\n AudioDirectorOptions,\n EnvironmentDirectorOptions,\n} from \"@realitycollective/webxr-environment\";\nimport { AudioDirector, EnvironmentDirector } from \"@realitycollective/webxr-environment\";\nimport type { IWSDKEnvironmentPortOptions } from \"./environment-port.js\";\nimport { IWSDKEnvironmentPort } from \"./environment-port.js\";\nimport type { IWSDKAudioPortOptions } from \"./audio-port.js\";\nimport { IWSDKAudioPort } from \"./audio-port.js\";\n\nexport type { IWSDKEnvironmentPortOptions } from \"./environment-port.js\";\nexport { IWSDKEnvironmentPort } from \"./environment-port.js\";\nexport type { IWSDKAudioPortOptions } from \"./audio-port.js\";\nexport { IWSDKAudioPort } from \"./audio-port.js\";\nexport type { IWSDKWorldSensingPortOptions } from \"./world-sensing-port.js\";\nexport { IWSDKWorldSensingPort } from \"./world-sensing-port.js\";\n\nexport * from \"@realitycollective/webxr-environment\";\n\nexport interface IWSDKEnvironmentOptions\n extends EnvironmentDirectorOptions,\n IWSDKEnvironmentPortOptions {\n /** Audio director + port options. Omit to set up the environment only. */\n readonly audio?: AudioDirectorOptions & IWSDKAudioPortOptions;\n}\n\nexport interface IWSDKEnvironmentSetup {\n readonly environment: EnvironmentDirector;\n readonly environmentPort: IWSDKEnvironmentPort;\n readonly audio: AudioDirector | null;\n readonly audioPort: IWSDKAudioPort | null;\n /** Tear both directors down and remove everything they created. */\n dispose(): void;\n}\n\nconst hosts = new WeakMap<World, IWSDKEnvironmentSetup>();\n\n/** The setup registered for a world, if `registerEnvironment` has run. */\nexport function environmentFor(world: World): IWSDKEnvironmentSetup | undefined {\n return hosts.get(world);\n}\n\n/**\n * The per-frame tick.\n *\n * Neither director owns a loop, so something has to drive them, and on IWSDK\n * that something is a system - which means the environment stops advancing\n * when the session loses focus, exactly like the rest of the app.\n * `registerEnvironment` registers this for you; it is exported so an app that\n * builds its own system schedule can place it deliberately.\n *\n * IWSDK hands a system its delta in SECONDS and the directors take\n * milliseconds. That conversion happens here, once.\n */\nexport class EnvironmentSystem extends createSystem({}) {\n override update(delta: number): void {\n const setup = hosts.get(this.world as unknown as World);\n if (setup === undefined) return;\n const deltaMs = delta * 1000;\n setup.environment.update(deltaMs);\n setup.audio?.update(deltaMs);\n }\n}\n\n/**\n * One call to wire the environment (and optionally the audio) into an IWSDK\n * world, and register the system that ticks them.\n *\n * ```ts\n * const env = registerEnvironment(world, {\n * presets: STOCK_PRESETS,\n * initial: VOID,\n * audio: { cues: [{ id: \"hum\", src: \"/audio/hum.mp3\", bus: \"ambience\", loop: true }] },\n * });\n * env.environment.transition(\"dusk\", { durationMs: 8000 });\n * ```\n *\n * Passthrough is NOT read from the session here - push it in from whatever\n * already tracks capabilities (`env.environment.setPassthrough(...)`). The\n * session belongs to the platform layer, not to the environment.\n */\nexport function registerEnvironment(\n world: World,\n options: IWSDKEnvironmentOptions = {},\n): IWSDKEnvironmentSetup {\n const existing = hosts.get(world);\n if (existing !== undefined) return existing;\n\n const environmentPort = new IWSDKEnvironmentPort(world, options);\n const environment = new EnvironmentDirector(environmentPort, options);\n\n let audio: AudioDirector | null = null;\n let audioPort: IWSDKAudioPort | null = null;\n if (options.audio !== undefined) {\n audioPort = new IWSDKAudioPort(world, options.audio);\n audio = new AudioDirector(audioPort, options.audio);\n }\n\n const setup: IWSDKEnvironmentSetup = {\n environment,\n environmentPort,\n audio,\n audioPort,\n dispose() {\n audio?.dispose();\n environment.dispose();\n hosts.delete(world);\n },\n };\n hosts.set(world, setup);\n world.registerSystem(EnvironmentSystem);\n return setup;\n}\n\nexport type { Entity as IWSDKEntity };\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,cAAc,sCAAsC,CAAC;AAkBrD,MAAM,KAAK,GAAG,IAAI,OAAO,EAAgC,CAAC;AAE1D,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,iBAAkB,SAAQ,YAAY,CAAC,EAAE,CAAC;IAC5C,MAAM,CAAC,KAAa;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAyB,CAAC,CAAC;QACxD,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAChC,MAAM,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;QAC7B,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAY,EACZ,UAAmC,EAAE;IAErC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAE5C,MAAM,eAAe,GAAG,IAAI,oBAAoB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IAEtE,IAAI,KAAK,GAAyB,IAAI,CAAC;IACvC,IAAI,SAAS,GAA0B,IAAI,CAAC;IAC5C,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,SAAS,GAAG,IAAI,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACrD,KAAK,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,KAAK,GAA0B;QACnC,WAAW;QACX,eAAe;QACf,KAAK;QACL,SAAS;QACT,OAAO;YACL,KAAK,EAAE,OAAO,EAAE,CAAC;YACjB,WAAW,CAAC,OAAO,EAAE,CAAC;YACtB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;KACF,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACxB,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * `@realitycollective/iwsdk-environment` - the Meta IWSDK adapter.\n *\n * Re-exports the whole engine-free core, so an app installs this package and\n * nothing else.\n */\nimport type { Entity, World } from \"@iwsdk/core\";\nimport { createSystem } from \"./create-system.js\";\nimport type {\n AudioDirectorOptions,\n EnvironmentDirectorOptions,\n} from \"@realitycollective/webxr-environment\";\nimport { AudioDirector, EnvironmentDirector } from \"@realitycollective/webxr-environment\";\nimport type { IWSDKEnvironmentPortOptions } from \"./environment-port.js\";\nimport { IWSDKEnvironmentPort } from \"./environment-port.js\";\nimport type { IWSDKAudioPortOptions } from \"./audio-port.js\";\nimport { IWSDKAudioPort } from \"./audio-port.js\";\n\nexport type { IWSDKEnvironmentPortOptions } from \"./environment-port.js\";\nexport { IWSDKEnvironmentPort } from \"./environment-port.js\";\nexport type { IWSDKAudioPortOptions } from \"./audio-port.js\";\nexport { IWSDKAudioPort } from \"./audio-port.js\";\nexport type { IWSDKWorldSensingPortOptions } from \"./world-sensing-port.js\";\nexport { IWSDKWorldSensingPort } from \"./world-sensing-port.js\";\n\nexport * from \"@realitycollective/webxr-environment\";\n\nexport interface IWSDKEnvironmentOptions\n extends EnvironmentDirectorOptions,\n IWSDKEnvironmentPortOptions {\n /** Audio director + port options. Omit to set up the environment only. */\n readonly audio?: AudioDirectorOptions & IWSDKAudioPortOptions;\n}\n\nexport interface IWSDKEnvironmentSetup {\n readonly environment: EnvironmentDirector;\n readonly environmentPort: IWSDKEnvironmentPort;\n readonly audio: AudioDirector | null;\n readonly audioPort: IWSDKAudioPort | null;\n /** Tear both directors down and remove everything they created. */\n dispose(): void;\n}\n\nconst hosts = new WeakMap<World, IWSDKEnvironmentSetup>();\n\n/** The setup registered for a world, if `registerEnvironment` has run. */\nexport function environmentFor(world: World): IWSDKEnvironmentSetup | undefined {\n return hosts.get(world);\n}\n\n/**\n * The per-frame tick.\n *\n * Neither director owns a loop, so something has to drive them, and on IWSDK\n * that something is a system - which means the environment stops advancing\n * when the session loses focus, exactly like the rest of the app.\n * `registerEnvironment` registers this for you; it is exported so an app that\n * builds its own system schedule can place it deliberately.\n *\n * IWSDK hands a system its delta in SECONDS and the directors take\n * milliseconds. That conversion happens here, once.\n */\nexport class EnvironmentSystem extends createSystem({}) {\n override update(delta: number): void {\n const setup = hosts.get(this.world as unknown as World);\n if (setup === undefined) return;\n const deltaMs = delta * 1000;\n setup.environment.update(deltaMs);\n setup.audio?.update(deltaMs);\n }\n}\n\n/**\n * One call to wire the environment (and optionally the audio) into an IWSDK\n * world, and register the system that ticks them.\n *\n * ```ts\n * const env = registerEnvironment(world, {\n * presets: STOCK_PRESETS,\n * initial: VOID,\n * audio: { cues: [{ id: \"hum\", src: \"/audio/hum.mp3\", bus: \"ambience\", loop: true }] },\n * });\n * env.environment.transition(\"dusk\", { durationMs: 8000 });\n * ```\n *\n * Passthrough is NOT read from the session here - push it in from whatever\n * already tracks capabilities (`env.environment.setPassthrough(...)`). The\n * session belongs to the platform layer, not to the environment.\n */\nexport function registerEnvironment(\n world: World,\n options: IWSDKEnvironmentOptions = {},\n): IWSDKEnvironmentSetup {\n const existing = hosts.get(world);\n if (existing !== undefined) return existing;\n\n const environmentPort = new IWSDKEnvironmentPort(world, options);\n const environment = new EnvironmentDirector(environmentPort, options);\n\n let audio: AudioDirector | null = null;\n let audioPort: IWSDKAudioPort | null = null;\n if (options.audio !== undefined) {\n audioPort = new IWSDKAudioPort(world, options.audio);\n audio = new AudioDirector(audioPort, options.audio);\n }\n\n const setup: IWSDKEnvironmentSetup = {\n environment,\n environmentPort,\n audio,\n audioPort,\n dispose() {\n audio?.dispose();\n environment.dispose();\n hosts.delete(world);\n },\n };\n hosts.set(world, setup);\n world.registerSystem(EnvironmentSystem);\n return setup;\n}\n\nexport type { Entity as IWSDKEntity };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realitycollective/iwsdk-environment",
3
- "version": "0.1.0-preview.2",
3
+ "version": "0.1.0",
4
4
  "description": "Meta IWSDK adapter for the Reality Collective WebXR Environment Extensions - drives IWSDK's own DomeGradient, light components, transform entities and AudioSource machinery from the engine-free @realitycollective/webxr-environment core, with a one-call registerEnvironment(world) setup and an ECS system that ticks the directors. Re-exports the core.",
5
5
  "keywords": [
6
6
  "realitycollective",
@@ -35,7 +35,7 @@
35
35
  "typecheck": "tsc -p tsconfig.json --noEmit"
36
36
  },
37
37
  "dependencies": {
38
- "@realitycollective/webxr-environment": "^0.1.0-preview.2"
38
+ "@realitycollective/webxr-environment": "^0.1.0"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@iwsdk/core": ">=0.5.0 <0.6.0",