@plasius/gpu-shared 0.1.2 → 0.1.4

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
@@ -16,6 +16,41 @@ All notable changes to this project will be documented in this file.
16
16
  - **Security**
17
17
  - (placeholder)
18
18
 
19
+ ## [0.1.4] - 2026-03-26
20
+
21
+ - **Added**
22
+ - (placeholder)
23
+
24
+ - **Changed**
25
+ - (placeholder)
26
+
27
+ - **Fixed**
28
+ - (placeholder)
29
+
30
+ - **Security**
31
+ - (placeholder)
32
+
33
+ ## [0.1.3] - 2026-03-26
34
+
35
+ - **Added**
36
+ - Public-contract tests that lock the package export surface for the shared
37
+ runtime and bundled brigantine asset.
38
+ - Public `destroy()` teardown hook on `mountGpuShowcase()` so browser consumers can clean up the shared runtime safely on route/page unmount.
39
+
40
+ - **Changed**
41
+ - Documented the import-map pattern for browser demos so consumers stay on the
42
+ published `@plasius/gpu-shared` package surface instead of deep internal
43
+ paths.
44
+ - README usage now documents the shared teardown contract for public consumers.
45
+
46
+ - **Fixed**
47
+ - Shared brigantine asset resolution now falls back to an inline browser-safe
48
+ data URL when a consuming bundler does not provide a valid module base URL,
49
+ preventing `Invalid URL` crashes in hosted GPU demo catalogs.
50
+
51
+ - **Security**
52
+ - (placeholder)
53
+
19
54
  ## [0.1.2] - 2026-03-23
20
55
 
21
56
  - **Added**
@@ -65,3 +100,5 @@ All notable changes to this project will be documented in this file.
65
100
  [0.1.0]: https://github.com/Plasius-LTD/gpu-shared/releases/tag/v0.1.0
66
101
  [0.1.1]: https://github.com/Plasius-LTD/gpu-shared/releases/tag/v0.1.1
67
102
  [0.1.2]: https://github.com/Plasius-LTD/gpu-shared/releases/tag/v0.1.2
103
+ [0.1.3]: https://github.com/Plasius-LTD/gpu-shared/releases/tag/v0.1.3
104
+ [0.1.4]: https://github.com/Plasius-LTD/gpu-shared/releases/tag/v0.1.4
package/README.md CHANGED
@@ -34,12 +34,29 @@ npm install @plasius/gpu-shared
34
34
  ```js
35
35
  import { mountGpuShowcase } from "@plasius/gpu-shared";
36
36
 
37
- await mountGpuShowcase({
37
+ const showcase = await mountGpuShowcase({
38
38
  root: document.getElementById("app"),
39
39
  packageName: "@plasius/gpu-demo-viewer",
40
40
  title: "Flag by the Sea",
41
41
  subtitle: "Shared 3D validation scene for the gpu-* family.",
42
42
  });
43
+
44
+ // Teardown is safe to call repeatedly from a route/page cleanup.
45
+ showcase.destroy();
46
+ ```
47
+
48
+ For browser-only demos served without a bundler, keep the import surface on the
49
+ published package name and resolve it with an import map rather than importing a
50
+ viewer-private or workspace-private source file:
51
+
52
+ ```html
53
+ <script type="importmap">
54
+ {
55
+ "imports": {
56
+ "@plasius/gpu-shared": "../node_modules/@plasius/gpu-shared/dist/index.js"
57
+ }
58
+ }
59
+ </script>
43
60
  ```
44
61
 
45
62
  ## Asset Helpers
@@ -80,6 +97,7 @@ surface for these family demos.
80
97
  ## API
81
98
 
82
99
  - `mountGpuShowcase(options)`
100
+ - Returns `{ state, shipModel, canvas, destroy() }`
83
101
  - `loadGltfModel(url)`
84
102
  - `resolveShowcaseAssetUrl(baseUrl?)`
85
103
  - `showcaseFocusModes`
@@ -0,0 +1,14 @@
1
+ // src/asset-url.js
2
+ var INLINE_BRIGANTINE_GLTF_URL = "data:application/json;base64,ewogICJhc3NldCI6IHsKICAgICJ2ZXJzaW9uIjogIjIuMCIsCiAgICAiZ2VuZXJhdG9yIjogIlBsYXNpdXMgZGVtbyBhc3NldCBnZW5lcmF0b3IiCiAgfSwKICAic2NlbmUiOiAwLAogICJzY2VuZXMiOiBbCiAgICB7CiAgICAgICJub2RlcyI6IFswXQogICAgfQogIF0sCiAgIm5vZGVzIjogWwogICAgewogICAgICAibWVzaCI6IDAsCiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUiLAogICAgICAiZXh0cmFzIjogewogICAgICAgICJwaHlzaWNzIjogewogICAgICAgICAgInNoYXBlIjogImJveCIsCiAgICAgICAgICAiaGFsZkV4dGVudHMiOiBbMS4zNSwgMC45NSwgMy45XSwKICAgICAgICAgICJtYXNzIjogMzIwMCwKICAgICAgICAgICJyZXN0aXR1dGlvbiI6IDAuMjIsCiAgICAgICAgICAibGluZWFyRGFtcGluZyI6IDAuMDQsCiAgICAgICAgICAiYW5ndWxhckRhbXBpbmciOiAwLjA4LAogICAgICAgICAgIndhdGVybGluZSI6IDAuNDIKICAgICAgICB9CiAgICAgIH0KICAgIH0KICBdLAogICJtZXNoZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUtaHVsbCIsCiAgICAgICJwcmltaXRpdmVzIjogWwogICAgICAgIHsKICAgICAgICAgICJhdHRyaWJ1dGVzIjogewogICAgICAgICAgICAiUE9TSVRJT04iOiAwCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxLAogICAgICAgICAgIm1hdGVyaWFsIjogMAogICAgICAgIH0KICAgICAgXQogICAgfQogIF0sCiAgIm1hdGVyaWFscyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAicGFpbnRlZC1odWxsIiwKICAgICAgInBick1ldGFsbGljUm91Z2huZXNzIjogewogICAgICAgICJiYXNlQ29sb3JGYWN0b3IiOiBbMC41NiwgMC4zMywgMC4yMiwgMV0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC4wOCwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC45MgogICAgICB9CiAgICB9CiAgXSwKICAiYnVmZmVycyI6IFsKICAgIHsKICAgICAgInVyaSI6ICJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsbXBtWnZ3QUFBTC9OekV6QW1wbVpQd0FBQUwvTnpFekF6Y3lzdnpNenM3NHpNN08vemN5c1B6TXpzNzR6TTdPL0FBQ2d2ODNNVEwzTnpNdy9BQUNnUDgzTVRMM056TXcvQUFBQUFPeFJPTDR6TTROQUFBQUFBR1ptNWo0QUFIQkFNek56dnpNenN6NmFtUm5BTXpOelB6TXpzejZhbVJuQXpjeE12ejBLMXo3TnpFdy96Y3hNUHowSzF6N056RXcvQUFBQUFETXpjejltWm1hL0FBQUNBQU1BQUFBREFBRUFBZ0FFQUFVQUFnQUZBQU1BQkFBSEFBVUFCQUFHQUFjQUJRQUhBQVlBQUFBQkFBa0FBQUFKQUFnQUNBQUpBQXdBQWdBSUFBd0FBd0FNQUFrQUFnQU1BQW9BQXdBTEFBd0FBZ0FLQUFRQUF3QUZBQXNBQ2dBTUFBc0FBQUFJQUFJQUFRQURBQWtBQkFBS0FBWUFCUUFHQUFzQUFnQUtBQXNBQWdBTEFBTUEiLAogICAgICAiYnl0ZUxlbmd0aCI6IDI5NAogICAgfQogIF0sCiAgImJ1ZmZlclZpZXdzIjogWwogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiYnl0ZUxlbmd0aCI6IDE1NiwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAxNTYsCiAgICAgICJieXRlTGVuZ3RoIjogMTM4LAogICAgICAidGFyZ2V0IjogMzQ5NjMKICAgIH0KICBdLAogICJhY2Nlc3NvcnMiOiBbCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDEzLAogICAgICAidHlwZSI6ICJWRUMzIiwKICAgICAgIm1pbiI6IFstMS4zNSwgLTAuNSwgLTMuMl0sCiAgICAgICJtYXgiOiBbMS4zNSwgMC45NSwgNC4xXQogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAxLAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyMywKICAgICAgImNvdW50IjogNjksCiAgICAgICJ0eXBlIjogIlNDQUxBUiIsCiAgICAgICJtYXgiOiBbMTJdLAogICAgICAibWluIjogWzBdCiAgICB9CiAgXQp9Cg==";
3
+ function resolveShowcaseAssetUrl(baseUrl = import.meta.url) {
4
+ try {
5
+ return new URL("../assets/brigantine.gltf", baseUrl);
6
+ } catch {
7
+ return new URL(INLINE_BRIGANTINE_GLTF_URL);
8
+ }
9
+ }
10
+
11
+ export {
12
+ resolveShowcaseAssetUrl
13
+ };
14
+ //# sourceMappingURL=chunk-S5NCFNKJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/asset-url.js"],"sourcesContent":["const INLINE_BRIGANTINE_GLTF_URL =\n \"data:application/json;base64,ewogICJhc3NldCI6IHsKICAgICJ2ZXJzaW9uIjogIjIuMCIsCiAgICAiZ2VuZXJhdG9yIjogIlBsYXNpdXMgZGVtbyBhc3NldCBnZW5lcmF0b3IiCiAgfSwKICAic2NlbmUiOiAwLAogICJzY2VuZXMiOiBbCiAgICB7CiAgICAgICJub2RlcyI6IFswXQogICAgfQogIF0sCiAgIm5vZGVzIjogWwogICAgewogICAgICAibWVzaCI6IDAsCiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUiLAogICAgICAiZXh0cmFzIjogewogICAgICAgICJwaHlzaWNzIjogewogICAgICAgICAgInNoYXBlIjogImJveCIsCiAgICAgICAgICAiaGFsZkV4dGVudHMiOiBbMS4zNSwgMC45NSwgMy45XSwKICAgICAgICAgICJtYXNzIjogMzIwMCwKICAgICAgICAgICJyZXN0aXR1dGlvbiI6IDAuMjIsCiAgICAgICAgICAibGluZWFyRGFtcGluZyI6IDAuMDQsCiAgICAgICAgICAiYW5ndWxhckRhbXBpbmciOiAwLjA4LAogICAgICAgICAgIndhdGVybGluZSI6IDAuNDIKICAgICAgICB9CiAgICAgIH0KICAgIH0KICBdLAogICJtZXNoZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUtaHVsbCIsCiAgICAgICJwcmltaXRpdmVzIjogWwogICAgICAgIHsKICAgICAgICAgICJhdHRyaWJ1dGVzIjogewogICAgICAgICAgICAiUE9TSVRJT04iOiAwCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxLAogICAgICAgICAgIm1hdGVyaWFsIjogMAogICAgICAgIH0KICAgICAgXQogICAgfQogIF0sCiAgIm1hdGVyaWFscyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAicGFpbnRlZC1odWxsIiwKICAgICAgInBick1ldGFsbGljUm91Z2huZXNzIjogewogICAgICAgICJiYXNlQ29sb3JGYWN0b3IiOiBbMC41NiwgMC4zMywgMC4yMiwgMV0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC4wOCwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC45MgogICAgICB9CiAgICB9CiAgXSwKICAiYnVmZmVycyI6IFsKICAgIHsKICAgICAgInVyaSI6ICJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsbXBtWnZ3QUFBTC9OekV6QW1wbVpQd0FBQUwvTnpFekF6Y3lzdnpNenM3NHpNN08vemN5c1B6TXpzNzR6TTdPL0FBQ2d2ODNNVEwzTnpNdy9BQUNnUDgzTVRMM056TXcvQUFBQUFPeFJPTDR6TTROQUFBQUFBR1ptNWo0QUFIQkFNek56dnpNenN6NmFtUm5BTXpOelB6TXpzejZhbVJuQXpjeE12ejBLMXo3TnpFdy96Y3hNUHowSzF6N056RXcvQUFBQUFETXpjejltWm1hL0FBQUNBQU1BQUFBREFBRUFBZ0FFQUFVQUFnQUZBQU1BQkFBSEFBVUFCQUFHQUFjQUJRQUhBQVlBQUFBQkFBa0FBQUFKQUFnQUNBQUpBQXdBQWdBSUFBd0FBd0FNQUFrQUFnQU1BQW9BQXdBTEFBd0FBZ0FLQUFRQUF3QUZBQXNBQ2dBTUFBc0FBQUFJQUFJQUFRQURBQWtBQkFBS0FBWUFCUUFHQUFzQUFnQUtBQXNBQWdBTEFBTUEiLAogICAgICAiYnl0ZUxlbmd0aCI6IDI5NAogICAgfQogIF0sCiAgImJ1ZmZlclZpZXdzIjogWwogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiYnl0ZUxlbmd0aCI6IDE1NiwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAxNTYsCiAgICAgICJieXRlTGVuZ3RoIjogMTM4LAogICAgICAidGFyZ2V0IjogMzQ5NjMKICAgIH0KICBdLAogICJhY2Nlc3NvcnMiOiBbCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDEzLAogICAgICAidHlwZSI6ICJWRUMzIiwKICAgICAgIm1pbiI6IFstMS4zNSwgLTAuNSwgLTMuMl0sCiAgICAgICJtYXgiOiBbMS4zNSwgMC45NSwgNC4xXQogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAxLAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyMywKICAgICAgImNvdW50IjogNjksCiAgICAgICJ0eXBlIjogIlNDQUxBUiIsCiAgICAgICJtYXgiOiBbMTJdLAogICAgICAibWluIjogWzBdCiAgICB9CiAgXQp9Cg==\";\n\nexport function resolveShowcaseAssetUrl(baseUrl = import.meta.url) {\n try {\n return new URL(\"../assets/brigantine.gltf\", baseUrl);\n } catch {\n return new URL(INLINE_BRIGANTINE_GLTF_URL);\n }\n}\n"],"mappings":";AAAA,IAAM,6BACJ;AAEK,SAAS,wBAAwB,UAAU,YAAY,KAAK;AACjE,MAAI;AACF,WAAO,IAAI,IAAI,6BAA6B,OAAO;AAAA,EACrD,QAAQ;AACN,WAAO,IAAI,IAAI,0BAA0B;AAAA,EAC3C;AACF;","names":[]}
package/dist/index.cjs CHANGED
@@ -19,6 +19,22 @@ var __copyProps = (to, from, except, desc) => {
19
19
  };
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
 
22
+ // src/asset-url.js
23
+ function resolveShowcaseAssetUrl(baseUrl2 = import_meta.url) {
24
+ try {
25
+ return new URL("../assets/brigantine.gltf", baseUrl2);
26
+ } catch {
27
+ return new URL(INLINE_BRIGANTINE_GLTF_URL);
28
+ }
29
+ }
30
+ var import_meta, INLINE_BRIGANTINE_GLTF_URL;
31
+ var init_asset_url = __esm({
32
+ "src/asset-url.js"() {
33
+ import_meta = {};
34
+ INLINE_BRIGANTINE_GLTF_URL = "data:application/json;base64,ewogICJhc3NldCI6IHsKICAgICJ2ZXJzaW9uIjogIjIuMCIsCiAgICAiZ2VuZXJhdG9yIjogIlBsYXNpdXMgZGVtbyBhc3NldCBnZW5lcmF0b3IiCiAgfSwKICAic2NlbmUiOiAwLAogICJzY2VuZXMiOiBbCiAgICB7CiAgICAgICJub2RlcyI6IFswXQogICAgfQogIF0sCiAgIm5vZGVzIjogWwogICAgewogICAgICAibWVzaCI6IDAsCiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUiLAogICAgICAiZXh0cmFzIjogewogICAgICAgICJwaHlzaWNzIjogewogICAgICAgICAgInNoYXBlIjogImJveCIsCiAgICAgICAgICAiaGFsZkV4dGVudHMiOiBbMS4zNSwgMC45NSwgMy45XSwKICAgICAgICAgICJtYXNzIjogMzIwMCwKICAgICAgICAgICJyZXN0aXR1dGlvbiI6IDAuMjIsCiAgICAgICAgICAibGluZWFyRGFtcGluZyI6IDAuMDQsCiAgICAgICAgICAiYW5ndWxhckRhbXBpbmciOiAwLjA4LAogICAgICAgICAgIndhdGVybGluZSI6IDAuNDIKICAgICAgICB9CiAgICAgIH0KICAgIH0KICBdLAogICJtZXNoZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUtaHVsbCIsCiAgICAgICJwcmltaXRpdmVzIjogWwogICAgICAgIHsKICAgICAgICAgICJhdHRyaWJ1dGVzIjogewogICAgICAgICAgICAiUE9TSVRJT04iOiAwCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxLAogICAgICAgICAgIm1hdGVyaWFsIjogMAogICAgICAgIH0KICAgICAgXQogICAgfQogIF0sCiAgIm1hdGVyaWFscyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAicGFpbnRlZC1odWxsIiwKICAgICAgInBick1ldGFsbGljUm91Z2huZXNzIjogewogICAgICAgICJiYXNlQ29sb3JGYWN0b3IiOiBbMC41NiwgMC4zMywgMC4yMiwgMV0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC4wOCwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC45MgogICAgICB9CiAgICB9CiAgXSwKICAiYnVmZmVycyI6IFsKICAgIHsKICAgICAgInVyaSI6ICJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsbXBtWnZ3QUFBTC9OekV6QW1wbVpQd0FBQUwvTnpFekF6Y3lzdnpNenM3NHpNN08vemN5c1B6TXpzNzR6TTdPL0FBQ2d2ODNNVEwzTnpNdy9BQUNnUDgzTVRMM056TXcvQUFBQUFPeFJPTDR6TTROQUFBQUFBR1ptNWo0QUFIQkFNek56dnpNenN6NmFtUm5BTXpOelB6TXpzejZhbVJuQXpjeE12ejBLMXo3TnpFdy96Y3hNUHowSzF6N056RXcvQUFBQUFETXpjejltWm1hL0FBQUNBQU1BQUFBREFBRUFBZ0FFQUFVQUFnQUZBQU1BQkFBSEFBVUFCQUFHQUFjQUJRQUhBQVlBQUFBQkFBa0FBQUFKQUFnQUNBQUpBQXdBQWdBSUFBd0FBd0FNQUFrQUFnQU1BQW9BQXdBTEFBd0FBZ0FLQUFRQUF3QUZBQXNBQ2dBTUFBc0FBQUFJQUFJQUFRQURBQWtBQkFBS0FBWUFCUUFHQUFzQUFnQUtBQXNBQWdBTEFBTUEiLAogICAgICAiYnl0ZUxlbmd0aCI6IDI5NAogICAgfQogIF0sCiAgImJ1ZmZlclZpZXdzIjogWwogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiYnl0ZUxlbmd0aCI6IDE1NiwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAxNTYsCiAgICAgICJieXRlTGVuZ3RoIjogMTM4LAogICAgICAidGFyZ2V0IjogMzQ5NjMKICAgIH0KICBdLAogICJhY2Nlc3NvcnMiOiBbCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDEzLAogICAgICAidHlwZSI6ICJWRUMzIiwKICAgICAgIm1pbiI6IFstMS4zNSwgLTAuNSwgLTMuMl0sCiAgICAgICJtYXgiOiBbMS4zNSwgMC45NSwgNC4xXQogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAxLAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyMywKICAgICAgImNvdW50IjogNjksCiAgICAgICJ0eXBlIjogIlNDQUxBUiIsCiAgICAgICJtYXgiOiBbMTJdLAogICAgICAibWluIjogWzBdCiAgICB9CiAgXQp9Cg==";
35
+ }
36
+ });
37
+
22
38
  // src/gltf-loader.js
23
39
  var gltf_loader_exports = {};
24
40
  __export(gltf_loader_exports, {
@@ -2452,10 +2468,10 @@ function getLightingProfile(name = defaultLightingProfile) {
2452
2468
  }
2453
2469
  return profile;
2454
2470
  }
2455
- var import_meta, __require, baseUrl, techniqueSpecs, lightingTechniques, lightingTechniqueNames, defaultLightingTechnique, profileSpecs, lightingProfiles, lightingProfileNames, defaultLightingProfile, lightingDistanceBands, lightingWorkerQueueClass, lightingDebugOwner, lightingImportanceLevels, lightingBandPolicySpecs, lightingWorkerSpecPresets, lightingWorkerDagSpecs, lightingWorkerManifests, defaultTechnique, lightingPreludeWgslUrl, lightingJobLabels, lightingJobs;
2471
+ var import_meta2, __require, baseUrl, techniqueSpecs, lightingTechniques, lightingTechniqueNames, defaultLightingTechnique, profileSpecs, lightingProfiles, lightingProfileNames, defaultLightingProfile, lightingDistanceBands, lightingWorkerQueueClass, lightingDebugOwner, lightingImportanceLevels, lightingBandPolicySpecs, lightingWorkerSpecPresets, lightingWorkerDagSpecs, lightingWorkerManifests, defaultTechnique, lightingPreludeWgslUrl, lightingJobLabels, lightingJobs;
2456
2472
  var init_dist3 = __esm({
2457
2473
  "node_modules/@plasius/gpu-lighting/dist/index.js"() {
2458
- import_meta = {};
2474
+ import_meta2 = {};
2459
2475
  __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2460
2476
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
2461
2477
  }) : x)(function(x) {
@@ -2463,8 +2479,8 @@ var init_dist3 = __esm({
2463
2479
  throw Error('Dynamic require of "' + x + '" is not supported');
2464
2480
  });
2465
2481
  baseUrl = (() => {
2466
- if (typeof import_meta.url !== "undefined") {
2467
- return new URL("./index.js", import_meta.url);
2482
+ if (typeof import_meta2.url !== "undefined") {
2483
+ return new URL("./index.js", import_meta2.url);
2468
2484
  }
2469
2485
  if (typeof __filename !== "undefined" && typeof __require !== "undefined") {
2470
2486
  const { pathToFileURL } = __require("url");
@@ -6276,12 +6292,8 @@ var init_browser = __esm({
6276
6292
  var showcase_runtime_exports = {};
6277
6293
  __export(showcase_runtime_exports, {
6278
6294
  mountGpuShowcase: () => mountGpuShowcase,
6279
- resolveShowcaseAssetUrl: () => resolveShowcaseAssetUrl,
6280
6295
  showcaseFocusModes: () => showcaseFocusModes
6281
6296
  });
6282
- function resolveShowcaseAssetUrl(baseUrl2 = import_meta2.url) {
6283
- return new URL("../assets/brigantine.gltf", baseUrl2);
6284
- }
6285
6297
  function injectStyles() {
6286
6298
  if (document.getElementById(STYLE_ID)) {
6287
6299
  return;
@@ -7802,6 +7814,9 @@ function syncTextState(state, shipModel) {
7802
7814
  async function mountGpuShowcase(options = {}) {
7803
7815
  injectStyles();
7804
7816
  const root = options.root ?? document.body;
7817
+ const previousMarkup = root.innerHTML;
7818
+ const previousRenderGameToText = window.render_game_to_text;
7819
+ const previousAdvanceTime = window.advanceTime;
7805
7820
  const focus = options.focus ?? new URLSearchParams(window.location.search).get("focus") ?? "integrated";
7806
7821
  const dom = buildDemoDom(root, {
7807
7822
  packageName: options.packageName ?? "@plasius/gpu-demo-viewer",
@@ -7818,7 +7833,12 @@ async function mountGpuShowcase(options = {}) {
7818
7833
  state.demoDescription = resolveSceneDescription(state, options, shipModel).description;
7819
7834
  syncTextState(state, shipModel);
7820
7835
  const ctx = dom.canvas.getContext("2d");
7836
+ let destroyed = false;
7837
+ let frameHandle = null;
7821
7838
  const renderFrame = (nowMs) => {
7839
+ if (destroyed) {
7840
+ return;
7841
+ }
7822
7842
  if (!state.paused) {
7823
7843
  if (state.lastTimeMs == null) {
7824
7844
  state.lastTimeMs = nowMs;
@@ -7835,27 +7855,53 @@ async function mountGpuShowcase(options = {}) {
7835
7855
  state.demoDescription = resolveSceneDescription(state, options, shipModel).description;
7836
7856
  renderScene(ctx, dom.canvas, state, shipModel, dom);
7837
7857
  syncTextState(state, shipModel);
7838
- requestAnimationFrame(renderFrame);
7858
+ frameHandle = requestAnimationFrame(renderFrame);
7839
7859
  };
7840
- dom.pauseButton.addEventListener("click", () => {
7860
+ const handlePauseClick = () => {
7841
7861
  state.paused = !state.paused;
7842
7862
  dom.pauseButton.textContent = state.paused ? "Resume" : "Pause";
7843
- });
7844
- dom.stressToggle.addEventListener("change", () => {
7863
+ };
7864
+ const handleStressChange = () => {
7845
7865
  state.stress = dom.stressToggle.checked;
7846
- });
7847
- dom.focusMode.addEventListener("change", () => {
7866
+ };
7867
+ const handleFocusChange = () => {
7848
7868
  state.focus = dom.focusMode.value;
7849
7869
  Object.assign(state.camera, {
7850
7870
  ...CAMERA_PRESETS[state.focus],
7851
7871
  target: vec3(...CAMERA_PRESETS[state.focus].target)
7852
7872
  });
7853
- });
7854
- requestAnimationFrame(renderFrame);
7873
+ };
7874
+ dom.pauseButton.addEventListener("click", handlePauseClick);
7875
+ dom.stressToggle.addEventListener("change", handleStressChange);
7876
+ dom.focusMode.addEventListener("change", handleFocusChange);
7877
+ frameHandle = requestAnimationFrame(renderFrame);
7855
7878
  return {
7856
7879
  state,
7857
7880
  shipModel,
7858
- canvas: dom.canvas
7881
+ canvas: dom.canvas,
7882
+ destroy() {
7883
+ if (destroyed) {
7884
+ return;
7885
+ }
7886
+ destroyed = true;
7887
+ if (frameHandle != null) {
7888
+ cancelAnimationFrame(frameHandle);
7889
+ }
7890
+ dom.pauseButton.removeEventListener("click", handlePauseClick);
7891
+ dom.stressToggle.removeEventListener("change", handleStressChange);
7892
+ dom.focusMode.removeEventListener("change", handleFocusChange);
7893
+ root.innerHTML = previousMarkup;
7894
+ if (typeof previousRenderGameToText === "function") {
7895
+ window.render_game_to_text = previousRenderGameToText;
7896
+ } else {
7897
+ delete window.render_game_to_text;
7898
+ }
7899
+ if (typeof previousAdvanceTime === "function") {
7900
+ window.advanceTime = previousAdvanceTime;
7901
+ } else {
7902
+ delete window.advanceTime;
7903
+ }
7904
+ }
7859
7905
  };
7860
7906
  }
7861
7907
  function updatePhysicsSnapshot(state, shipModel) {
@@ -7878,7 +7924,7 @@ function updatePhysicsSnapshot(state, shipModel) {
7878
7924
  }
7879
7925
  });
7880
7926
  }
7881
- var import_meta2, STYLE_ID, DEFAULT_TITLE, DEFAULT_SUBTITLE, CAMERA_PRESETS, showcaseFocusModes, SCENE_NOTES, UNIT_BOX_MESH;
7927
+ var STYLE_ID, DEFAULT_TITLE, DEFAULT_SUBTITLE, CAMERA_PRESETS, showcaseFocusModes, SCENE_NOTES, UNIT_BOX_MESH;
7882
7928
  var init_showcase_runtime = __esm({
7883
7929
  "src/showcase-runtime.js"() {
7884
7930
  init_dist();
@@ -7887,8 +7933,8 @@ var init_showcase_runtime = __esm({
7887
7933
  init_dist4();
7888
7934
  init_dist5();
7889
7935
  init_browser();
7936
+ init_asset_url();
7890
7937
  init_gltf_loader();
7891
- import_meta2 = {};
7892
7938
  STYLE_ID = "plasius-shared-3d-showcase-style";
7893
7939
  DEFAULT_TITLE = "Flag by the Sea";
7894
7940
  DEFAULT_SUBTITLE = "Shared 3D validation scene using GLTF ships, cloth, fluid continuity, adaptive performance, and telemetry.";
@@ -7982,11 +8028,11 @@ var index_exports = {};
7982
8028
  __export(index_exports, {
7983
8029
  loadGltfModel: () => loadGltfModel2,
7984
8030
  mountGpuShowcase: () => mountGpuShowcase2,
7985
- resolveShowcaseAssetUrl: () => resolveShowcaseAssetUrl2,
8031
+ resolveShowcaseAssetUrl: () => resolveShowcaseAssetUrl,
7986
8032
  showcaseFocusModes: () => showcaseFocusModes2
7987
8033
  });
7988
8034
  module.exports = __toCommonJS(index_exports);
7989
- var import_meta3 = {};
8035
+ init_asset_url();
7990
8036
  var showcaseFocusModes2 = Object.freeze([
7991
8037
  "integrated",
7992
8038
  "lighting",
@@ -7996,9 +8042,6 @@ var showcaseFocusModes2 = Object.freeze([
7996
8042
  "performance",
7997
8043
  "debug"
7998
8044
  ]);
7999
- function resolveShowcaseAssetUrl2(baseUrl2 = import_meta3.url) {
8000
- return new URL("../assets/brigantine.gltf", baseUrl2);
8001
- }
8002
8045
  async function loadGltfModel2(url) {
8003
8046
  const module2 = await Promise.resolve().then(() => (init_gltf_loader(), gltf_loader_exports));
8004
8047
  return module2.loadGltfModel(url);