From fdd3ba3e7c181d6a4a1eacd4a0daac125bf81790 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Mon, 21 Jul 2025 15:35:30 +0200 Subject: [PATCH 01/41] added components for graphs changes in animation panel --- index.html | 41 ++++++++++++++++++++++++++++++----------- src/ui/sass.scss | 13 +++++++++++++ src/ui/ui.js | 10 ++++++++++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index 033b125d..a8e3708a 100644 --- a/index.html +++ b/index.html @@ -343,17 +343,17 @@

glTF Validator

- + + @@ -361,15 +361,24 @@

glTF Validator

-

Animation

- - - + +

Interactivity Graphs

+ + + +
+ + + +
+ - - Animation + +
+ + + + + + + +
diff --git a/src/ui/sass.scss b/src/ui/sass.scss index 77c1cb41..ad843047 100644 --- a/src/ui/sass.scss +++ b/src/ui/sass.scss @@ -400,3 +400,16 @@ button.button 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } + +// Outlined Reset button style for Graphs tab +.button.is-outlined { + border: 1.5px solid #87c540; + color: #f2f2f2; + background: transparent; + box-shadow: none; +} + +// Margin for custom events section in Graphs tab +.tabContent .subtitle + div[style*="margin-top: 2.5em;"] { + margin-top: 2.5em !important; +} diff --git a/src/ui/ui.js b/src/ui/ui.js index d36522e9..2d46e712 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -392,6 +392,16 @@ const appCreated = createApp({ toggleUI() { this.uiVisible = !this.uiVisible; }, + resetAnimation() { + // Pause and immediately play to reset animation + this.setAnimationState(false); + this.animationPlayChanged.next(false); + // Small timeout to ensure state change + setTimeout(() => { + this.setAnimationState(true); + this.animationPlayChanged.next(true); + }, 50); + }, } }); From bfe45895bf8e86ef49052e6cd7791384cabd0a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Wed, 23 Jul 2025 16:09:33 +0200 Subject: [PATCH 02/41] Preserve gltf structure for root extensions --- glTF-Sample-Renderer | 2 +- src/logic/uimodel.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 2ae24a17..3809aefb 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 2ae24a17aa5f65604b8cdb9f5c8029f7b3347cf4 +Subproject commit 3809aefbb92f4cd3bcb8a2326b5644f15c0c954b diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index ce46ad7a..567e2691 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -202,8 +202,8 @@ class UIModel this.app.selectedAnimations = state.animationIndices; - if (gltf && gltf.variants) { - this.app.materialVariants = ["None", ...gltf.variants.map(variant => variant?.name ?? "Unnamed")]; + if (gltf && gltf?.extensions?.KHR_materials_variants?.variants !== undefined) { + this.app.materialVariants = ["None", ...gltf.extensions.KHR_materials_variants.variants.map(variant => variant?.name ?? "Unnamed")]; } else { this.app.materialVariants = ["None"]; } From 7dd55e153cd47ed7676555fda4218cd7bca66c23 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Wed, 23 Jul 2025 16:53:10 +0200 Subject: [PATCH 03/41] Interactivity components --- index.html | 58 ++++++++++++++++++++++++++++++++++++++++++++-------- src/ui/ui.js | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/index.html b/index.html index a8e3708a..7cc3faf3 100644 --- a/index.html +++ b/index.html @@ -363,7 +363,6 @@

glTF Validator

@click="collapseActiveTab($event, 3)">

Interactivity Graphs

-
@@ -377,25 +376,66 @@

Interactivity Graphs

- + - - +
+ {{ animation.title }} - - + +
-
- +
+ +
+ + +
+
+ + +

{{ customEventNumberInputError }}

+
+
+ + +

{{ customEventNumberInputWholeError }}

+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
diff --git a/src/ui/ui.js b/src/ui/ui.js index 2d46e712..2975c999 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -72,6 +72,7 @@ const appCreated = createApp({ selectedVariant: "None", selectedAnimations: [], disabledAnimations: [], + selectedGraph: null, validationReport: {}, validationReportDescription: {}, @@ -117,6 +118,16 @@ const appCreated = createApp({ // these are handles for certain ui change related things environmentVisiblePrefState: true, volumeEnabledPrefState: true, + customEventEnabled: false, + customEventNumberInput: 0, + customEventNumberInputError: '', + customEventNumberInputWhole: '', + customEventNumberInputWholeError: '', + customEventMatrix2x2: [0, 0, 0, 0], + customEventMatrix3x3: [0, 0, 0, 0, 0, 0, 0, 0, 0], + customEventMatrix4x4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + customEventSendClicked: new Subject(), + customEventSendFeedback: false, }; }, watch: { @@ -402,6 +413,45 @@ const appCreated = createApp({ this.animationPlayChanged.next(true); }, 50); }, + sendCustomEvent() { + this.customEventSendClicked.next({ + enabled: this.customEventEnabled, + number: this.customEventNumberInput, + matrix2x2: this.customEventMatrix2x2, + matrix3x3: this.customEventMatrix3x3, + matrix4x4: this.customEventMatrix4x4 + }); + this.customEventSendFeedback = true; + setTimeout(() => { + this.customEventSendFeedback = false; + }, 3000); + }, + validateCustomEventNumberInput() { + const val = this.customEventNumberInput; + if (val === '' || val === null || val === undefined) { + this.customEventNumberInputError = ''; + return; + } + // Only allow floats (must have a decimal point) + if (!/^[-+]?\d*\.\d+$/.test(String(val))) { + this.customEventNumberInputError = 'Please enter a floating point number (e.g., 1.23)'; + } else { + this.customEventNumberInputError = ''; + } + }, + validateCustomEventNumberInputWhole() { + const val = this.customEventNumberInputWhole; + if (val === '' || val === null || val === undefined) { + this.customEventNumberInputWholeError = ''; + return; + } + // Only allow whole numbers (no decimal point) + if (!/^[-+]?\d+$/.test(String(val))) { + this.customEventNumberInputWholeError = 'Please enter a whole number (e.g., 5)'; + } else { + this.customEventNumberInputWholeError = ''; + } + }, } }); From b8847474a32289e9e493a132f80afc2d2c188a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Wed, 23 Jul 2025 17:22:15 +0200 Subject: [PATCH 04/41] Remove unnecessary code --- index.html | 6 ++---- src/ui/ui.js | 14 -------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 7cc3faf3..7976c30e 100644 --- a/index.html +++ b/index.html @@ -380,7 +380,7 @@

Interactivity Graphs
- + {{ animation.title }}
@@ -399,9 +399,8 @@

Interactivity Graphs
- + -

{{ customEventNumberInputError }}

@@ -431,7 +430,6 @@

Interactivity Graphs Send Sent diff --git a/src/ui/ui.js b/src/ui/ui.js index 2975c999..9f6e11ac 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -120,7 +120,6 @@ const appCreated = createApp({ volumeEnabledPrefState: true, customEventEnabled: false, customEventNumberInput: 0, - customEventNumberInputError: '', customEventNumberInputWhole: '', customEventNumberInputWholeError: '', customEventMatrix2x2: [0, 0, 0, 0], @@ -426,19 +425,6 @@ const appCreated = createApp({ this.customEventSendFeedback = false; }, 3000); }, - validateCustomEventNumberInput() { - const val = this.customEventNumberInput; - if (val === '' || val === null || val === undefined) { - this.customEventNumberInputError = ''; - return; - } - // Only allow floats (must have a decimal point) - if (!/^[-+]?\d*\.\d+$/.test(String(val))) { - this.customEventNumberInputError = 'Please enter a floating point number (e.g., 1.23)'; - } else { - this.customEventNumberInputError = ''; - } - }, validateCustomEventNumberInputWhole() { const val = this.customEventNumberInputWhole; if (val === '' || val === null || val === undefined) { From 498530d4dca8382e7f9a4131020340e7be539769 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Thu, 24 Jul 2025 11:55:16 +0200 Subject: [PATCH 05/41] Added vectors in the interactivity panel --- index.html | 54 ++++++++++++++++++++++++++++++++++++++++++++-------- src/ui/ui.js | 15 +++++++++------ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/index.html b/index.html index 7976c30e..5bce43ae 100644 --- a/index.html +++ b/index.html @@ -47,7 +47,7 @@ + + diff --git a/src/ui/ui.js b/src/ui/ui.js index 9f6e11ac..889da281 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -125,8 +125,10 @@ const appCreated = createApp({ customEventMatrix2x2: [0, 0, 0, 0], customEventMatrix3x3: [0, 0, 0, 0, 0, 0, 0, 0, 0], customEventMatrix4x4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + customEventVector2: [0, 0], + customEventVector3: [0, 0, 0], + customEventVector4: [0, 0, 0, 0], customEventSendClicked: new Subject(), - customEventSendFeedback: false, }; }, watch: { @@ -420,10 +422,11 @@ const appCreated = createApp({ matrix3x3: this.customEventMatrix3x3, matrix4x4: this.customEventMatrix4x4 }); - this.customEventSendFeedback = true; - setTimeout(() => { - this.customEventSendFeedback = false; - }, 3000); + this.$buefy.toast.open({ + message: 'Custom event sent successfully!', + type: 'is-success', + duration: 3000 + }); }, validateCustomEventNumberInputWhole() { const val = this.customEventNumberInputWhole; @@ -445,7 +448,7 @@ appCreated.use(Buefy); // general components appCreated.component('toggle-button', { - props: ['ontext', 'offtext'], + props: ['ontext', 'offtext', 'btnClass'], template:'#toggleButtonTemplate', data(){ return { From 7bfd3c32003c3ca67fd61244613cc08073f66ae8 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Thu, 24 Jul 2025 14:26:10 +0200 Subject: [PATCH 06/41] Rename Vector and states of Reset button --- index.html | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 5bce43ae..d36e9ba6 100644 --- a/index.html +++ b/index.html @@ -372,7 +372,7 @@

Interactivity Graphs - @@ -428,19 +428,19 @@

Interactivity Graphs

- +
- +
- +
@@ -610,6 +610,15 @@

Advanced Controls

.round-green-btn:active { background: #5e8c2f; } +.reset-btn-green { + transition: background 0.15s; +} +.reset-btn-green:hover { + background: #385117 !important; +} +.reset-btn-green:active { + background: #5e8c2f !important; +} From 17ea8a8023d5de1ea0f3125c19e705b01097f3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 25 Jul 2025 17:14:39 +0200 Subject: [PATCH 07/41] Minor UI fixes --- index.html | 11 ++++++----- src/ui/ui.js | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index d36e9ba6..d3ffa98c 100644 --- a/index.html +++ b/index.html @@ -363,9 +363,9 @@

glTF Validator

@click="collapseActiveTab($event, 3)">

Interactivity Graphs

- + -
+
Interactivity GraphsCustom events - +
- - + +
@@ -531,6 +531,7 @@

Advanced Controls

Skinning
Morphing + Interactivity diff --git a/src/ui/ui.js b/src/ui/ui.js index 889da281..16157cd0 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -93,6 +93,7 @@ const appCreated = createApp({ toneMap: "Khronos PBR Neutral", skinning: true, morphing: true, + interactivity: true, clearcoatEnabled: true, sheenEnabled: true, transmissionEnabled: true, @@ -120,7 +121,7 @@ const appCreated = createApp({ volumeEnabledPrefState: true, customEventEnabled: false, customEventNumberInput: 0, - customEventNumberInputWhole: '', + customEventNumberInputWhole: 0, customEventNumberInputWholeError: '', customEventMatrix2x2: [0, 0, 0, 0], customEventMatrix3x3: [0, 0, 0, 0, 0, 0, 0, 0, 0], From 24f27afad01a2ea324b9a2bc5d6bd022ac3ed0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Wed, 30 Jul 2025 16:11:14 +0200 Subject: [PATCH 08/41] Add graph controller --- glTF-Sample-Renderer | 2 +- package-lock.json | 26 ++++++++++++++++++++++++++ src/main.js | 27 +++++++++++++++++---------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 3809aefb..a3e98d43 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 3809aefbb92f4cd3bcb8a2326b5644f15c0c954b +Subproject commit a3e98d43c40b0326907adca1f522dd9bdd8a879f diff --git a/package-lock.json b/package-lock.json index 80bdf44f..5706ced5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,11 +45,24 @@ "@rollup/rollup-linux-x64-gnu": "^4.23.0" } }, + "../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine": { + "name": "khr_interactivity_authoring_engine", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "gl-matrix": "^3.4.3" + }, + "devDependencies": { + "@types/node": "^24.1.0", + "typescript": "^5.8.3" + } + }, "glTF-Sample-Renderer": { "name": "@khronosgroup/gltf-viewer", "version": "1.1.0", "license": "Apache-2.0", "dependencies": { + "@khronosgroup/khr_interactivity_authoring_engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "fast-png": "^6.2.0", "gl-matrix": "^3.2.1", "globals": "^15.5.0", @@ -1111,6 +1124,10 @@ "resolved": "glTF-Sample-Renderer", "link": true }, + "node_modules/@khronosgroup/khr_interactivity_authoring_engine": { + "resolved": "../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "link": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -5745,6 +5762,7 @@ "@khronosgroup/gltf-viewer": { "version": "file:glTF-Sample-Renderer", "requires": { + "@khronosgroup/khr_interactivity_authoring_engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-wasm": "^6.2.2", @@ -6304,6 +6322,14 @@ } } }, + "@khronosgroup/khr_interactivity_authoring_engine": { + "version": "file:../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "requires": { + "@types/node": "^24.1.0", + "gl-matrix": "^3.4.3", + "typescript": "^5.8.3" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, diff --git a/src/main.js b/src/main.js index c2cdabf6..c5d6c70b 100644 --- a/src/main.js +++ b/src/main.js @@ -147,18 +147,24 @@ export default async () => { state.userCamera.orbit(yaw, pitch); state.userCamera.zoomBy(distance); - // Try to start as many animations as possible without generating conficts. - state.animationIndices = []; - for (let i = 0; i < gltf.animations.length; i++) { - if ( - !gltf - .nonDisjointAnimations(state.animationIndices) - .includes(i) - ) { - state.animationIndices.push(i); + if (state.gltf?.extensions?.KHR_interactivity.graphs !== undefined) { + state.graphController.initializeGraphs(state); + const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; + state.graphController.startGraph(graphIndex); + } else { + // Try to start as many animations as possible without generating conficts. + state.animationIndices = []; + for (let i = 0; i < gltf.animations.length; i++) { + if ( + !gltf + .nonDisjointAnimations(state.animationIndices) + .includes(i) + ) { + state.animationIndices.push(i); + } } + state.animationTimer.start(); } - state.animationTimer.start(); } uiModel.exitLoadingState(); @@ -478,6 +484,7 @@ export default async () => { canvas.width = Math.floor(canvas.clientWidth * devicePixelRatio); canvas.height = Math.floor(canvas.clientHeight * devicePixelRatio); redraw |= !state.animationTimer.paused && state.animationIndices.length > 0; + redraw |= state.graphController.playing; redraw |= past.width != canvas.width || past.height != canvas.height; // Refit view if canvas changes significantly From 672b7ace248e46e4baf6d7aadf41d50b7592381d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 31 Jul 2025 15:35:25 +0200 Subject: [PATCH 09/41] Add graph selection logic to UI --- glTF-Sample-Renderer | 2 +- index.html | 84 ++++++++++++++++++++++---------------------- src/logic/uimodel.js | 13 +++++++ src/main.js | 36 +++++++++++++------ src/ui/sass.scss | 29 +++++++++++++++ src/ui/ui.js | 39 +++++++++++++++----- 6 files changed, 141 insertions(+), 62 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index a3e98d43..89f53f75 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit a3e98d43c40b0326907adca1f522dd9bdd8a879f +Subproject commit 89f53f7578984c7598204213d45e88ac450dbbf0 diff --git a/index.html b/index.html index d3ffa98c..314f7cd0 100644 --- a/index.html +++ b/index.html @@ -343,27 +343,28 @@

glTF Validator

- - + + -
+
- -

Interactivity Graphs

- +

Animations

+
Interactivity Graphs
- - No animations available +
- + {{ animation.title }} + +
+
+
+
+ +

Interactivity Graphs

+ + +
+ + + + +
+ + + +
+ + {{ graph.title }}
@@ -591,35 +622,4 @@

Advanced Controls

- - diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index 567e2691..3802f953 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -77,7 +77,9 @@ class UIModel ); this.animationPlay = app.animationPlayChanged.pipe(); + this.graphPlay = app.graphPlayChanged.pipe(); this.activeAnimations = app.selectedAnimationsChanged.pipe(); + this.selectedGraph = app.selectedGraphChanged.pipe(); const canvas = document.getElementById("canvas"); canvas.addEventListener('dragenter', () => this.app.showDropDownOverlay = true); @@ -214,6 +216,17 @@ class UIModel index: index })); + // Set up interactivity graphs if available + if (gltf?.extensions?.KHR_interactivity?.graphs !== undefined && state.renderingParameters.enabledExtensions.KHR_interactivity) { + this.app.graphs = gltf.extensions.KHR_interactivity.graphs.map((graph, index) => ({ + title: graph.name ?? `Graph ${index}`, + index: index + })); + this.app.selectedGraph = state.graphController.graphIndex; + } else { + this.app.graphs = []; + } + this.app.xmp = gltf?.extensions?.KHR_xmp_json_ld?.packets[gltf?.asset?.extensions?.KHR_xmp_json_ld.packet] ?? null; }); } diff --git a/src/main.js b/src/main.js index c5d6c70b..de1e7bb6 100644 --- a/src/main.js +++ b/src/main.js @@ -147,22 +147,24 @@ export default async () => { state.userCamera.orbit(yaw, pitch); state.userCamera.zoomBy(distance); + state.animationIndices = []; + for (let i = 0; i < gltf.animations.length; i++) { + if ( + !gltf + .nonDisjointAnimations(state.animationIndices) + .includes(i) + ) { + state.animationIndices.push(i); + } + } + if (state.gltf?.extensions?.KHR_interactivity.graphs !== undefined) { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); } else { // Try to start as many animations as possible without generating conficts. - state.animationIndices = []; - for (let i = 0; i < gltf.animations.length; i++) { - if ( - !gltf - .nonDisjointAnimations(state.animationIndices) - .includes(i) - ) { - state.animationIndices.push(i); - } - } + state.graphController.stopGraph(); state.animationTimer.start(); } } @@ -433,11 +435,25 @@ export default async () => { } }); + uiModel.graphPlay.subscribe((graphPlay) => { + if (graphPlay) { + state.graphController.playGraph(); + } else { + state.graphController.pauseGraph(); + } + }); + uiModel.activeAnimations.subscribe( (animations) => (state.animationIndices = animations) ); listenForRedraw(uiModel.activeAnimations); + uiModel.selectedGraph.subscribe((graphIndex) => { + if (graphIndex !== null && graphIndex !== undefined) { + state.graphController.startGraph(graphIndex); + } + }); + uiModel.hdr.subscribe((hdr) => { resourceLoader.loadEnvironment(hdr.hdr_path).then((environment) => { state.environment = environment; diff --git a/src/ui/sass.scss b/src/ui/sass.scss index ad843047..2287ed57 100644 --- a/src/ui/sass.scss +++ b/src/ui/sass.scss @@ -413,3 +413,32 @@ button.button .tabContent .subtitle + div[style*="margin-top: 2.5em;"] { margin-top: 2.5em !important; } + +.round-green-btn { + background: #87c540; + color: #f2f2f2; + width: 90px; + min-width: 90px; + max-width: 90px; + border: none; + transition: background 0.15s; + text-align: center; + justify-content: center; + align-items: center; + display: inline-flex; +} +.round-green-btn:hover { + background: #6fa32e; +} +.round-green-btn:active { + background: #5e8c2f; +} +.reset-btn-green { + transition: background 0.15s; +} +.reset-btn-green:hover { + background: #385117 !important; +} +.reset-btn-green:active { + background: #5e8c2f !important; +} \ No newline at end of file diff --git a/src/ui/ui.js b/src/ui/ui.js index 16157cd0..903b0fb7 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -10,6 +10,7 @@ const appCreated = createApp({ flavourChanged: new Subject(), sceneChanged: new Subject(), cameraChanged: new Subject(), + selectedGraphChanged: new Subject(), debugchannelChanged: new Subject(), tonemapChanged: new Subject(), @@ -23,6 +24,7 @@ const appCreated = createApp({ environmentRotationChanged: new Subject(), animationPlayChanged: new Subject(), + graphPlayChanged: new Subject(), variantChanged: new Subject(), exposureChanged: new Subject(), @@ -58,6 +60,7 @@ const appCreated = createApp({ materialVariants: ["None"], animations: [{title: "None"}], + graphs: [], tonemaps: [{title: "None"}], debugchannels: [{title: "None"}], xmp: [{title: "xmp"}], @@ -135,6 +138,9 @@ const appCreated = createApp({ watch: { selectedAnimations: function (newValue) { this.selectedAnimationsChanged.next(newValue); + }, + selectedGraph: function (newValue) { + this.selectedGraphChanged.next(newValue); } }, beforeMount: function(){ @@ -212,6 +218,17 @@ const appCreated = createApp({ }); }, + computed: { + hasInteractivityGraphs() { + return this.graphs && this.graphs.length > 0; + }, + showAnimationsTab() { + return !this.hasInteractivityGraphs; + }, + showGraphsTab() { + return this.graphs && this.graphs.length > 0 && this.interactivity; + } + }, methods: { async copyToClipboard(text) { @@ -311,7 +328,15 @@ const appCreated = createApp({ }, setAnimationState: function(value) { - this.$refs.animationState.setState(value); + if (this.$refs.animationState) { + this.$refs.animationState.setState(value); + } + }, + setGraphState: function(value) + { + if (this.$refs.graphState) { + this.$refs.graphState.setState(value); + } }, iblTriggered: function(value) { @@ -406,14 +431,10 @@ const appCreated = createApp({ this.uiVisible = !this.uiVisible; }, resetAnimation() { - // Pause and immediately play to reset animation - this.setAnimationState(false); - this.animationPlayChanged.next(false); - // Small timeout to ensure state change - setTimeout(() => { - this.setAnimationState(true); - this.animationPlayChanged.next(true); - }, 50); + //TODO + }, + resetGraph() { + //TODO }, sendCustomEvent() { this.customEventSendClicked.next({ From 9f8f8752d5305861c9bd0b9a15b3b05ec52d2a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 31 Jul 2025 16:46:03 +0200 Subject: [PATCH 10/41] WIP add support for custom events --- index.html | 180 ++++++++++++++++++++++++++++++------------- src/logic/uimodel.js | 3 + src/main.js | 7 ++ src/ui/ui.js | 83 ++++++++++++++++---- 4 files changed, 208 insertions(+), 65 deletions(-) diff --git a/index.html b/index.html index 314f7cd0..ebdca315 100644 --- a/index.html +++ b/index.html @@ -419,65 +419,141 @@

Interactivity Graphs -
+
- - - + + -
- - -
-
- - -
-
- - -

{{ customEventNumberInputWholeError }}

-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- + + +
+
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ +
+ + +
+ +
+ + +
+
+
+ + +
+ +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+
+ + +
+ +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
-
+
diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index 3802f953..5d1de0ff 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -78,6 +78,7 @@ class UIModel this.animationPlay = app.animationPlayChanged.pipe(); this.graphPlay = app.graphPlayChanged.pipe(); + this.customEventSend = app.customEventSendClicked.pipe(); this.activeAnimations = app.selectedAnimationsChanged.pipe(); this.selectedGraph = app.selectedGraphChanged.pipe(); @@ -223,8 +224,10 @@ class UIModel index: index })); this.app.selectedGraph = state.graphController.graphIndex; + this.app.customEvents = state.graphController.customEvents || []; } else { this.app.graphs = []; + this.app.customEvents = []; } this.app.xmp = gltf?.extensions?.KHR_xmp_json_ld?.packets[gltf?.asset?.extensions?.KHR_xmp_json_ld.packet] ?? null; diff --git a/src/main.js b/src/main.js index de1e7bb6..6e5ddb89 100644 --- a/src/main.js +++ b/src/main.js @@ -454,6 +454,13 @@ export default async () => { } }); + uiModel.customEventSend.subscribe((eventData) => { + if (eventData && eventData.eventId) { + state.graphController.dispatchEvent(eventData.eventId, eventData.values); + console.log('Sending custom event:', eventData.eventId, eventData.values); + } + }); + uiModel.hdr.subscribe((hdr) => { resourceLoader.loadEnvironment(hdr.hdr_path).then((environment) => { state.environment = environment; diff --git a/src/ui/ui.js b/src/ui/ui.js index 903b0fb7..62112aa5 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -122,6 +122,9 @@ const appCreated = createApp({ // these are handles for certain ui change related things environmentVisiblePrefState: true, volumeEnabledPrefState: true, + customEvents: [], + selectedCustomEvent: null, + customEventValues: {}, customEventEnabled: false, customEventNumberInput: 0, customEventNumberInputWhole: 0, @@ -141,6 +144,9 @@ const appCreated = createApp({ }, selectedGraph: function (newValue) { this.selectedGraphChanged.next(newValue); + }, + selectedCustomEvent: function (newValue) { + this.updateCustomEventValues(newValue); } }, beforeMount: function(){ @@ -222,15 +228,26 @@ const appCreated = createApp({ hasInteractivityGraphs() { return this.graphs && this.graphs.length > 0; }, - showAnimationsTab() { - return !this.hasInteractivityGraphs; - }, showGraphsTab() { - return this.graphs && this.graphs.length > 0 && this.interactivity; + return this.hasInteractivityGraphs; + }, + currentCustomEvent() { + if (!this.selectedCustomEvent || !this.customEvents) return null; + return this.customEvents.find(event => event.id === this.selectedCustomEvent); + }, + customEventInputs() { + if (!this.currentCustomEvent) return []; + const event = this.currentCustomEvent; + if (!event.values) return []; + + return Object.keys(event.values).map(key => ({ + name: key, + type: event.values[key].type, + value: event.values[key].value + })); } }, - methods: - { + methods: { async copyToClipboard(text) { try { await navigator.clipboard.writeText(text); @@ -436,16 +453,56 @@ const appCreated = createApp({ resetGraph() { //TODO }, + updateCustomEventValues(selectedEventId) { + if (!selectedEventId || !this.customEvents) { + this.customEventValues = {}; + return; + } + + const event = this.customEvents.find(e => e.id === selectedEventId); + if (!event || !event.values) { + this.customEventValues = {}; + return; + } + + // Initialize all input values based on the event definition + const values = {}; + Object.keys(event.values).forEach(key => { + const valueDefn = event.values[key]; + values[key] = valueDefn.value !== undefined ? valueDefn.value : this.getDefaultValue(valueDefn.type); + }); + this.customEventValues = values; + }, + getDefaultValue(type) { + switch(type) { + case 'bool': return false; + case 'int': return 0; + case 'float': return 0.0; + case 'float2': return [0, 0]; + case 'float3': return [0, 0, 0]; + case 'float4': return [0, 0, 0, 0]; + case 'float2x2': return [1, 0, 0, 1]; + case 'float3x3': return [1, 0, 0, 0, 1, 0, 0, 0, 1]; + case 'float4x4': return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + default: return null; + } + }, sendCustomEvent() { + if (!this.selectedCustomEvent || !this.currentCustomEvent) { + this.$buefy.toast.open({ + message: 'Please select a custom event first', + type: 'is-warning', + duration: 3000 + }); + return; + } + this.customEventSendClicked.next({ - enabled: this.customEventEnabled, - number: this.customEventNumberInput, - matrix2x2: this.customEventMatrix2x2, - matrix3x3: this.customEventMatrix3x3, - matrix4x4: this.customEventMatrix4x4 + eventId: this.selectedCustomEvent, + values: this.customEventValues }); this.$buefy.toast.open({ - message: 'Custom event sent successfully!', + message: `Custom event '${this.selectedCustomEvent}' sent successfully!`, type: 'is-success', duration: 3000 }); @@ -462,7 +519,7 @@ const appCreated = createApp({ } else { this.customEventNumberInputWholeError = ''; } - }, + } } }); From 9683f98e90f9cabc3caae67736f8f912b76b6de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 1 Aug 2025 12:15:59 +0200 Subject: [PATCH 11/41] Change styling of number inputs --- index.html | 90 +++++++++++++++++------------------------------- src/ui/sass.scss | 26 ++++++++++++++ src/ui/ui.js | 1 + 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/index.html b/index.html index ebdca315..9f8e2ada 100644 --- a/index.html +++ b/index.html @@ -441,28 +441,27 @@

Interactivity Graphs
- + + +
- +
- -
- - -
- -
- - +
+
+ + + +
@@ -471,23 +470,12 @@

Interactivity Graphs
- -
- - - -
- -
- - - -
- -
- - - +
+
+ + + +
@@ -496,42 +484,22 @@

Interactivity Graphs
- -
- - - - -
- -
- - - - -
- -
- - - - -
- -
- - - - +
+
+ + + +
-
- + + +
@@ -539,7 +507,9 @@

Interactivity Graphs
- + + +

@@ -547,7 +517,9 @@

Interactivity Graphs
- + + +

diff --git a/src/ui/sass.scss b/src/ui/sass.scss index 2287ed57..2f9a4802 100644 --- a/src/ui/sass.scss +++ b/src/ui/sass.scss @@ -441,4 +441,30 @@ button.button } .reset-btn-green:active { background: #5e8c2f !important; +} + +.matrixInput input { + width: 60px !important; + padding-right: 2px; + padding-left: 5px; +} + +.vectorInput input { + width: 60px !important; + padding-right: 2px; + padding-left: 5px; +} + +input[type="number"] { + -moz-appearance: textfield; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input:invalid { + border-color: #ff3860; } \ No newline at end of file diff --git a/src/ui/ui.js b/src/ui/ui.js index 62112aa5..5655fcfa 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -126,6 +126,7 @@ const appCreated = createApp({ selectedCustomEvent: null, customEventValues: {}, customEventEnabled: false, + customEventFocusedInput: null, customEventNumberInput: 0, customEventNumberInputWhole: 0, customEventNumberInputWholeError: '', From 2b4799ee77e6abaeee3f1417f277b7df1b027227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 1 Aug 2025 15:22:02 +0200 Subject: [PATCH 12/41] More UI fixes --- index.html | 21 ++++++++++++--------- src/ui/ui.js | 22 ---------------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/index.html b/index.html index 9f8e2ada..b646857b 100644 --- a/index.html +++ b/index.html @@ -441,15 +441,17 @@

Interactivity Graphs
- + - +
- + + +
@@ -458,7 +460,7 @@

Interactivity Graphs
- +
@@ -472,7 +474,7 @@

Interactivity Graphs
- +
@@ -486,18 +488,19 @@

Interactivity Graphs
- +

+

- +
@@ -507,7 +510,7 @@

Interactivity Graphs
- +
@@ -517,7 +520,7 @@

Interactivity Graphs
- +
diff --git a/src/ui/ui.js b/src/ui/ui.js index 5655fcfa..3b2c6851 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -127,15 +127,6 @@ const appCreated = createApp({ customEventValues: {}, customEventEnabled: false, customEventFocusedInput: null, - customEventNumberInput: 0, - customEventNumberInputWhole: 0, - customEventNumberInputWholeError: '', - customEventMatrix2x2: [0, 0, 0, 0], - customEventMatrix3x3: [0, 0, 0, 0, 0, 0, 0, 0, 0], - customEventMatrix4x4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - customEventVector2: [0, 0], - customEventVector3: [0, 0, 0], - customEventVector4: [0, 0, 0, 0], customEventSendClicked: new Subject(), }; }, @@ -507,19 +498,6 @@ const appCreated = createApp({ type: 'is-success', duration: 3000 }); - }, - validateCustomEventNumberInputWhole() { - const val = this.customEventNumberInputWhole; - if (val === '' || val === null || val === undefined) { - this.customEventNumberInputWholeError = ''; - return; - } - // Only allow whole numbers (no decimal point) - if (!/^[-+]?\d+$/.test(String(val))) { - this.customEventNumberInputWholeError = 'Please enter a whole number (e.g., 5)'; - } else { - this.customEventNumberInputWholeError = ''; - } } } }); From 484b11a50c35a6aabdb24248a8fd65a7561c21d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 1 Aug 2025 16:05:54 +0200 Subject: [PATCH 13/41] Fix event dispatch --- glTF-Sample-Renderer | 2 +- index.html | 16 ++++++++-------- src/main.js | 8 ++++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 89f53f75..ae8a8609 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 89f53f7578984c7598204213d45e88ac450dbbf0 +Subproject commit ae8a86094bec5322e7f3d7accf49fae9d2d52723 diff --git a/index.html b/index.html index b646857b..dfd702f2 100644 --- a/index.html +++ b/index.html @@ -442,7 +442,7 @@

Interactivity Graphs - +

@@ -450,7 +450,7 @@

Interactivity Graphs - +

@@ -461,7 +461,7 @@

Interactivity Graphs
- +

@@ -475,7 +475,7 @@

Interactivity Graphs
- +

@@ -489,7 +489,7 @@

Interactivity Graphs
- +

@@ -501,7 +501,7 @@

Interactivity Graphs{{ input.name }}
- +

@@ -511,7 +511,7 @@

Interactivity Graphs{{ input.name }}
- +

@@ -521,7 +521,7 @@

Interactivity Graphs{{ input.name }}
- +

diff --git a/src/main.js b/src/main.js index 6e5ddb89..de1a4b53 100644 --- a/src/main.js +++ b/src/main.js @@ -456,8 +456,12 @@ export default async () => { uiModel.customEventSend.subscribe((eventData) => { if (eventData && eventData.eventId) { - state.graphController.dispatchEvent(eventData.eventId, eventData.values); - console.log('Sending custom event:', eventData.eventId, eventData.values); + const values = {}; + for (const key in eventData.values) { + values[key] = eventData.values[key]; + + } + state.graphController.dispatchEvent(eventData.eventId, values); } }); From 99aa0d7fc925e08cfeb21cf7769b6ff349d80fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Mon, 4 Aug 2025 14:46:08 +0200 Subject: [PATCH 14/41] Auto select first element in dropdown --- index.html | 2 +- src/ui/ui.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index dfd702f2..3da748ca 100644 --- a/index.html +++ b/index.html @@ -422,7 +422,7 @@

Interactivity Graphs 0"> - + diff --git a/src/ui/ui.js b/src/ui/ui.js index 3b2c6851..67ed15fc 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -139,6 +139,12 @@ const appCreated = createApp({ }, selectedCustomEvent: function (newValue) { this.updateCustomEventValues(newValue); + }, + customEvents: function (newValue) { + // Auto-select the first custom event when the array is populated + if (newValue && newValue.length > 0 && !this.selectedCustomEvent) { + this.selectedCustomEvent = newValue[0].id; + } } }, beforeMount: function(){ From 4af3032df15207e1eddc5aeffd420ef839a7792f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Mon, 4 Aug 2025 15:33:31 +0200 Subject: [PATCH 15/41] Change tooltip --- index.html | 50 +++++++++++++++++++++++++++--------------------- src/ui/sass.scss | 8 ++++++-- src/ui/ui.js | 1 + 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index 3da748ca..09bf7387 100644 --- a/index.html +++ b/index.html @@ -442,7 +442,7 @@

Interactivity Graphs - +

@@ -450,80 +450,86 @@

Interactivity Graphs - +

+
- - - + +
-
+
+
- - - +
+
+
- - - + +
-
+
+
- - - +
+ +
+
+
- - - +
+ +
+
+
- - - +
+ +
+
diff --git a/src/ui/sass.scss b/src/ui/sass.scss index 2f9a4802..4b200305 100644 --- a/src/ui/sass.scss +++ b/src/ui/sass.scss @@ -56,6 +56,10 @@ $addColors: ( ); $colors: map-merge($colors, $addColors); +// Tooltip +$tooltip-arrow-size: 0px; +$tooltip-arrow-margin: 5px; + // Import Bulma and Buefy styles @import "../../node_modules/bulma/bulma"; @import "../../node_modules/@ntohq/buefy-next/src/scss/buefy"; @@ -445,13 +449,13 @@ button.button .matrixInput input { width: 60px !important; - padding-right: 2px; + padding-right: 6px; padding-left: 5px; } .vectorInput input { width: 60px !important; - padding-right: 2px; + padding-right: 6px; padding-left: 5px; } diff --git a/src/ui/ui.js b/src/ui/ui.js index 67ed15fc..8c8a30fd 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -127,6 +127,7 @@ const appCreated = createApp({ customEventValues: {}, customEventEnabled: false, customEventFocusedInput: null, + customEventFocusedIndex: null, customEventSendClicked: new Subject(), }; }, From 18cc19707aa9d8e4c4aefc279b97b23b449ff040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Mon, 4 Aug 2025 16:31:27 +0200 Subject: [PATCH 16/41] Disable send button if form is invalid --- index.html | 10 +++++----- src/ui/ui.js | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 09bf7387..91ee4d25 100644 --- a/index.html +++ b/index.html @@ -430,7 +430,7 @@

Interactivity Graphs -
+
@@ -442,7 +442,7 @@

Interactivity Graphs - +

@@ -450,7 +450,7 @@

Interactivity Graphs - +

@@ -532,10 +532,10 @@

Interactivity Graphs

- +
-
diff --git a/src/ui/ui.js b/src/ui/ui.js index 8c8a30fd..7d84eda3 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -128,6 +128,7 @@ const appCreated = createApp({ customEventEnabled: false, customEventFocusedInput: null, customEventFocusedIndex: null, + customEventValid: true, customEventSendClicked: new Subject(), }; }, @@ -146,6 +147,9 @@ const appCreated = createApp({ if (newValue && newValue.length > 0 && !this.selectedCustomEvent) { this.selectedCustomEvent = newValue[0].id; } + }, + customEventFocusedInput: function () { + this.customEventValid = this.isCustomEventValid(); } }, beforeMount: function(){ @@ -270,6 +274,12 @@ const appCreated = createApp({ document.body.removeChild(element); }, + isCustomEventValid() { + const form = document.getElementById("customEventForm"); + if (!form) return true; + return form.checkValidity(); + }, + /** * Creates a div string summarizing the given issues. * From dafb11492923c7d7687d794dc7707e7ed345d3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Mon, 4 Aug 2025 16:50:25 +0200 Subject: [PATCH 17/41] Update submodule --- glTF-Sample-Renderer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index ae8a8609..c57467e3 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit ae8a86094bec5322e7f3d7accf49fae9d2d52723 +Subproject commit c57467e38c983ea9e1ffb3e981b575893cfcc6cc From dedd8360bfdbe17038742ed4495bcdf09a52bc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Tue, 5 Aug 2025 18:07:35 +0200 Subject: [PATCH 18/41] Add play/pause/reset --- glTF-Sample-Renderer | 2 +- index.html | 4 ++-- src/logic/uimodel.js | 2 ++ src/main.js | 12 +++++++++++- src/ui/ui.js | 10 +++------- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index c57467e3..4867a709 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit c57467e38c983ea9e1ffb3e981b575893cfcc6cc +Subproject commit 4867a709dcb2123b936d33cce99bc9d77f3ceb47 diff --git a/index.html b/index.html index 91ee4d25..6827e9e9 100644 --- a/index.html +++ b/index.html @@ -374,7 +374,7 @@

Animations

@@ -404,7 +404,7 @@

Interactivity Graphs diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index 5d1de0ff..190d5995 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -78,6 +78,8 @@ class UIModel this.animationPlay = app.animationPlayChanged.pipe(); this.graphPlay = app.graphPlayChanged.pipe(); + this.animationReset = app.animationResetChanged.pipe(); + this.graphReset = app.graphResetChanged.pipe(); this.customEventSend = app.customEventSendClicked.pipe(); this.activeAnimations = app.selectedAnimationsChanged.pipe(); this.selectedGraph = app.selectedGraphChanged.pipe(); diff --git a/src/main.js b/src/main.js index de1a4b53..4e98d805 100644 --- a/src/main.js +++ b/src/main.js @@ -437,12 +437,22 @@ export default async () => { uiModel.graphPlay.subscribe((graphPlay) => { if (graphPlay) { - state.graphController.playGraph(); + state.graphController.resumeGraph(); } else { state.graphController.pauseGraph(); } }); + uiModel.animationReset.subscribe(() => { + state.animationTimer.reset(); + redraw = true; + }); + + uiModel.graphReset.subscribe(() => { + state.graphController.resetGraph(); + redraw = true; + }); + uiModel.activeAnimations.subscribe( (animations) => (state.animationIndices = animations) ); diff --git a/src/ui/ui.js b/src/ui/ui.js index 7d84eda3..8033299b 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -25,6 +25,8 @@ const appCreated = createApp({ environmentRotationChanged: new Subject(), animationPlayChanged: new Subject(), graphPlayChanged: new Subject(), + animationResetChanged: new Subject(), + graphResetChanged: new Subject(), variantChanged: new Subject(), exposureChanged: new Subject(), @@ -144,7 +146,7 @@ const appCreated = createApp({ }, customEvents: function (newValue) { // Auto-select the first custom event when the array is populated - if (newValue && newValue.length > 0 && !this.selectedCustomEvent) { + if (newValue && newValue.length > 0) { this.selectedCustomEvent = newValue[0].id; } }, @@ -456,12 +458,6 @@ const appCreated = createApp({ toggleUI() { this.uiVisible = !this.uiVisible; }, - resetAnimation() { - //TODO - }, - resetGraph() { - //TODO - }, updateCustomEventValues(selectedEventId) { if (!selectedEventId || !this.customEvents) { this.customEventValues = {}; From cb4f6aa2d96f19ae37d4e55e854afdb15fe4e047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Tue, 5 Aug 2025 18:20:50 +0200 Subject: [PATCH 19/41] Use v-model for toggle-button --- index.html | 4 ++-- src/logic/uimodel.js | 4 ++-- src/ui/ui.js | 36 ++++++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 6827e9e9..831f2e0e 100644 --- a/index.html +++ b/index.html @@ -368,7 +368,7 @@

Animations

@@ -398,7 +398,7 @@

Interactivity Graphs
diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index 190d5995..a8e753b5 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -206,14 +206,14 @@ class UIModel })); this.app.selectedAnimations = state.animationIndices; + this.app.animationState = true; + this.app.graphState = true; if (gltf && gltf?.extensions?.KHR_materials_variants?.variants !== undefined) { this.app.materialVariants = ["None", ...gltf.extensions.KHR_materials_variants.variants.map(variant => variant?.name ?? "Unnamed")]; } else { this.app.materialVariants = ["None"]; } - - this.app.setAnimationState(true); this.app.animations = gltf.animations.map((animation, index) => ({ title: animation.name ?? `Animation ${index}`, index: index diff --git a/src/ui/ui.js b/src/ui/ui.js index 8033299b..f4cb672c 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -79,6 +79,9 @@ const appCreated = createApp({ disabledAnimations: [], selectedGraph: null, + animationState: true, + graphState: true, + validationReport: {}, validationReportDescription: {}, @@ -354,18 +357,6 @@ const appCreated = createApp({ + infoDiv + `
`; }, - setAnimationState: function(value) - { - if (this.$refs.animationState) { - this.$refs.animationState.setState(value); - } - }, - setGraphState: function(value) - { - if (this.$refs.graphState) { - this.$refs.graphState.setState(value); - } - }, iblTriggered: function(value) { if(value == false) { @@ -519,7 +510,8 @@ appCreated.use(Buefy); // general components appCreated.component('toggle-button', { - props: ['ontext', 'offtext', 'btnClass'], + props: ['ontext', 'offtext', 'btnClass', 'modelValue'], + emits: ['buttonclicked', 'update:modelValue'], template:'#toggleButtonTemplate', data(){ return { @@ -528,7 +520,21 @@ appCreated.component('toggle-button', { }; }, mounted(){ - this.name = this.ontext; + this.name = this.offtext; + // Initialize state from modelValue prop if provided + if (this.modelValue !== undefined) { + this.isOn = this.modelValue; + this.name = this.isOn ? this.ontext : this.offtext; + } + }, + watch: { + // Watch for external changes to modelValue + modelValue(newValue) { + if (newValue !== this.isOn) { + this.isOn = newValue; + this.name = this.isOn ? this.ontext : this.offtext; + } + } }, methods: { @@ -537,11 +543,13 @@ appCreated.component('toggle-button', { this.isOn = !this.isOn; this.name = this.isOn ? this.ontext : this.offtext; this.$emit('buttonclicked', this.isOn); + this.$emit('update:modelValue', this.isOn); }, setState: function(value) { this.isOn = value; this.name = this.isOn ? this.ontext : this.offtext; + this.$emit('update:modelValue', this.isOn); } } }); From 9c02e9676c69a808a2278bc8156366c6ecb41627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Wed, 6 Aug 2025 18:26:57 +0200 Subject: [PATCH 20/41] Animation support for graphs --- glTF-Sample-Renderer | 2 +- src/main.js | 4 +--- src/ui/ui.js | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 4867a709..ca2a9043 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 4867a709dcb2123b936d33cce99bc9d77f3ceb47 +Subproject commit ca2a9043c78ce1d21a611be5b96e14477a53c8a1 diff --git a/src/main.js b/src/main.js index 4e98d805..8a9c9ed0 100644 --- a/src/main.js +++ b/src/main.js @@ -157,15 +157,13 @@ export default async () => { state.animationIndices.push(i); } } - + state.animationTimer.start(); if (state.gltf?.extensions?.KHR_interactivity.graphs !== undefined) { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); } else { - // Try to start as many animations as possible without generating conficts. state.graphController.stopGraph(); - state.animationTimer.start(); } } diff --git a/src/ui/ui.js b/src/ui/ui.js index f4cb672c..e960745b 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -237,7 +237,7 @@ const appCreated = createApp({ return this.graphs && this.graphs.length > 0; }, showGraphsTab() { - return this.hasInteractivityGraphs; + return this.hasInteractivityGraphs && this.interactivity; }, currentCustomEvent() { if (!this.selectedCustomEvent || !this.customEvents) return null; From e9f8d58771b090472013a06f598f82c681211706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 7 Aug 2025 16:04:23 +0200 Subject: [PATCH 21/41] Handle interacticity switch correctly with animations --- glTF-Sample-Renderer | 2 +- index.html | 2 +- src/logic/uimodel.js | 1 + src/main.js | 17 +++++++++++++++++ src/ui/ui.js | 1 + 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index ca2a9043..39b359c1 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit ca2a9043c78ce1d21a611be5b96e14477a53c8a1 +Subproject commit 39b359c16e85bcbef111e02f6fbb461f3935546f diff --git a/index.html b/index.html index 831f2e0e..b9a20e11 100644 --- a/index.html +++ b/index.html @@ -619,7 +619,7 @@

Advanced Controls

Skinning
Morphing - Interactivity + Interactivity diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index a8e753b5..2445fe4d 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -61,6 +61,7 @@ class UIModel this.addEnvironment = app.addEnvironmentChanged.pipe(); this.captureCanvas = app.captureCanvas.pipe(); this.cameraValuesExport = app.cameraExport.pipe(); + this.interactivityEnabled = app.interactivityChanged.pipe(); const initialClearColor = "#303542"; this.app.clearColor = initialClearColor; diff --git a/src/main.js b/src/main.js index 8a9c9ed0..7789bb4f 100644 --- a/src/main.js +++ b/src/main.js @@ -296,6 +296,21 @@ export default async () => { ); listenForRedraw(uiModel.morphingEnabled); + uiModel.interactivityEnabled.subscribe( + (interactivityEnabled) => + { + state.renderingParameters.enabledExtensions.KHR_interactivity = interactivityEnabled + if (interactivityEnabled) { + state.graphController.initializeGraphs(state); + const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; + state.graphController.startGraph(graphIndex); + } else { + state.graphController.stopGraph(); + } + } + ); + listenForRedraw(uiModel.interactivityEnabled); + uiModel.clearcoatEnabled.subscribe( (clearcoatEnabled) => (state.renderingParameters.enabledExtensions.KHR_materials_clearcoat = @@ -436,8 +451,10 @@ export default async () => { uiModel.graphPlay.subscribe((graphPlay) => { if (graphPlay) { state.graphController.resumeGraph(); + state.animationTimer.unpause(); } else { state.graphController.pauseGraph(); + state.animationTimer.pause(); } }); diff --git a/src/ui/ui.js b/src/ui/ui.js index e960745b..22ad91ad 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -20,6 +20,7 @@ const appCreated = createApp({ iblChanged: new Subject(), blurEnvChanged: new Subject(), morphingChanged: new Subject(), + interactivityChanged: new Subject(), colorChanged: new Subject(), environmentRotationChanged: new Subject(), From 53b63134ab0d2fee896664e0d1adb432ae922e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 21 Aug 2025 18:13:03 +0200 Subject: [PATCH 22/41] Fix UI issues --- glTF-Sample-Renderer | 2 +- src/main.js | 9 ++++++--- src/ui/ui.js | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index cc89a69c..df1343dc 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit cc89a69cf7c5ac84f342ce83df7ce9303b59dfb2 +Subproject commit df1343dca1d5b475edcf811a772afff1e927e697 diff --git a/src/main.js b/src/main.js index 49f01b5b..fdbbf263 100644 --- a/src/main.js +++ b/src/main.js @@ -163,7 +163,7 @@ export default async () => { const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); } else { - state.graphController.stopGraph(); + state.graphController.stopGraphEngine(); } } @@ -299,13 +299,16 @@ export default async () => { uiModel.interactivityEnabled.subscribe( (interactivityEnabled) => { - state.renderingParameters.enabledExtensions.KHR_interactivity = interactivityEnabled + state.renderingParameters.enabledExtensions.KHR_interactivity = interactivityEnabled; + if (state.gltf?.extensions?.KHR_interactivity === undefined) { + return; + } if (interactivityEnabled) { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); } else { - state.graphController.stopGraph(); + state.graphController.stopGraphEngine(); } } ); diff --git a/src/ui/ui.js b/src/ui/ui.js index 22ad91ad..95b81a3d 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -152,6 +152,8 @@ const appCreated = createApp({ // Auto-select the first custom event when the array is populated if (newValue && newValue.length > 0) { this.selectedCustomEvent = newValue[0].id; + } else { + this.selectedCustomEvent = null; } }, customEventFocusedInput: function () { From 70c61d93749f83e93ea0d248f393827bfaaa0745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 21 Aug 2025 18:14:23 +0200 Subject: [PATCH 23/41] Add extension toggles --- index.html | 5 ++++- src/logic/uimodel.js | 3 +++ src/main.js | 21 +++++++++++++++++++++ src/ui/ui.js | 6 ++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index b9a20e11..26bc9f6f 100644 --- a/index.html +++ b/index.html @@ -619,7 +619,10 @@

Advanced Controls

Skinning
Morphing - Interactivity + KHR_interactivity + KHR_node_hoverability + KHR_node_selectability + KHR_node_visibility diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index bac4665a..2df8132e 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -53,6 +53,9 @@ class UIModel this.dispersionEnabled = app.dispersionChanged.pipe(); this.specularEnabled = app.specularChanged.pipe(); this.emissiveStrengthEnabled = app.emissiveStrengthChanged.pipe(); + this.hoverabilityEnabled = app.hoverabilityChanged.pipe(); + this.selectabilityEnabled = app.selectabilityChanged.pipe(); + this.nodeVisibilityEnabled = app.nodeVisibilityChanged.pipe(); this.iblEnabled = app.iblChanged.pipe(); this.iblIntensity = app.iblIntensityChanged.pipe(); this.punctualLightsEnabled = app.punctualLightsChanged.pipe(); diff --git a/src/main.js b/src/main.js index fdbbf263..a79f9d3f 100644 --- a/src/main.js +++ b/src/main.js @@ -391,6 +391,27 @@ export default async () => { ); listenForRedraw(uiModel.emissiveStrengthEnabled); + uiModel.hoverabilityEnabled.subscribe( + (hoverabilityEnabled) => + (state.renderingParameters.enabledExtensions.KHR_node_hoverability = + hoverabilityEnabled) + ); + listenForRedraw(uiModel.hoverabilityEnabled); + + uiModel.selectabilityEnabled.subscribe( + (selectabilityEnabled) => + (state.renderingParameters.enabledExtensions.KHR_node_selectability = + selectabilityEnabled) + ); + listenForRedraw(uiModel.selectabilityEnabled); + + uiModel.nodeVisibilityEnabled.subscribe( + (nodeVisibilityEnabled) => + (state.renderingParameters.enabledExtensions.KHR_node_visibility = + nodeVisibilityEnabled) + ); + listenForRedraw(uiModel.nodeVisibilityEnabled); + uiModel.iblEnabled.subscribe( (iblEnabled) => (state.renderingParameters.useIBL = iblEnabled) ); diff --git a/src/ui/ui.js b/src/ui/ui.js index 95b81a3d..27638275 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -47,6 +47,9 @@ const appCreated = createApp({ dispersionChanged: new Subject(), specularChanged: new Subject(), emissiveStrengthChanged: new Subject(), + hoverabilityChanged: new Subject(), + selectabilityChanged: new Subject(), + nodeVisibilityChanged: new Subject(), renderEnvChanged: new Subject(), addEnvironmentChanged: new Subject(), selectedAnimationsChanged: new Subject(), @@ -114,6 +117,9 @@ const appCreated = createApp({ dispersionEnabled: true, specularEnabled: true, emissiveStrengthEnabled: true, + hoverabilityEnabled: true, + selectabilityEnabled: true, + nodeVisibilityEnabled: true, activeTab: 0, tabContentHidden: true, From 9b549ae38044e63d713c0ed82ac24aab3ca1b5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 29 Aug 2025 16:35:49 +0200 Subject: [PATCH 24/41] Float64 support --- glTF-Sample-Renderer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index df1343dc..bf2e06e7 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit df1343dca1d5b475edcf811a772afff1e927e697 +Subproject commit bf2e06e7ed2b2ce2a8415b3f423bf5cfefa3d678 From 63ddcae625395fcaee885764d6b891855285299d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 29 Aug 2025 16:38:08 +0200 Subject: [PATCH 25/41] Fix undefined bug --- src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index a79f9d3f..1370fc3f 100644 --- a/src/main.js +++ b/src/main.js @@ -158,7 +158,7 @@ export default async () => { } } state.animationTimer.start(); - if (state.gltf?.extensions?.KHR_interactivity.graphs !== undefined) { + if (state.gltf?.extensions?.KHR_interactivity?.graphs !== undefined) { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); From 6196b84cd2c836c75e1f78a89db5965ddf5aea8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 29 Aug 2025 16:38:41 +0200 Subject: [PATCH 26/41] Added picking pass Changes manually copied and adjusted from the gltfx branch --- glTF-Sample-Renderer | 2 +- src/logic/uimodel.js | 19 ++++++- src/main.js | 121 ++++++++++++++++++++++++++++++++++++++++++- src/ui/sass.scss | 4 ++ 4 files changed, 143 insertions(+), 3 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index bf2e06e7..81769f8c 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit bf2e06e7ed2b2ce2a8415b3f423bf5cfefa3d678 +Subproject commit 81769f8c0f24671a19155697765f44a05f0280d4 diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index 2df8132e..a51dfe56 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -192,6 +192,8 @@ class UIModel this.orbit = inputObservables.orbit; this.pan = inputObservables.pan; this.zoom = inputObservables.zoom; + this.selection = inputObservables.selection; + this.moveSelection = inputObservables.move; } attachGltfLoaded(gltfLoaded) @@ -384,10 +386,24 @@ const getInputObservables = (inputElement, app) => { const mouseMove = fromEvent(document, 'mousemove'); const mouseDown = fromEvent(inputElement, 'mousedown'); const mouseUp = merge(fromEvent(document, 'mouseup'), fromEvent(document, 'mouseleave')); + const click = fromEvent(inputElement, 'click'); inputElement.addEventListener('mousemove', event => event.preventDefault()); inputElement.addEventListener('mousedown', event => event.preventDefault()); inputElement.addEventListener('mouseup', event => event.preventDefault()); + inputElement.addEventListener('dblclick', event => event.preventDefault()); + inputElement.addEventListener('click', event => event.preventDefault()); + + const selection = click.pipe( + filter(event => event.button === 0), + map((clickEvent) => { + return {x: clickEvent.pageX, y: clickEvent.pageY}; + })); + + const move = mouseMove.pipe( + map((moveEvent) => { + return {x: moveEvent.pageX, y: moveEvent.pageY}; + })); const mouseOrbit = mouseDown.pipe( filter(event => event.button === 0 && event.shiftKey === false), @@ -472,7 +488,8 @@ const getInputObservables = (inputElement, app) => { observables.orbit = merge(mouseOrbit, touchOrbit); observables.pan = mousePan; observables.zoom = merge(mouseZoom, touchZoom); - + observables.selection = selection; + observables.move = move; // disable context menu inputElement.oncontextmenu = () => false; diff --git a/src/main.js b/src/main.js index 1370fc3f..512684a9 100644 --- a/src/main.js +++ b/src/main.js @@ -10,6 +10,7 @@ import { } from "./model_path_provider.js"; import {validateBytes} from "gltf-validator"; +import { mat4, quat, vec3 } from 'gl-matrix'; export default async () => { const canvas = document.getElementById("canvas"); @@ -551,6 +552,124 @@ export default async () => { listenForRedraw(gltfLoaded); + let select = false; + uiModel.selection.subscribe(selection => { + const devicePixelRatio = window.devicePixelRatio || 1; + state.pickingX = Math.floor(selection.x * devicePixelRatio); + state.pickingY = Math.floor(selection.y * devicePixelRatio); + state.triggerSelection = true; + select = true; + }); + listenForRedraw(uiModel.selection); + + let hover = false; + uiModel.moveSelection.subscribe(selection => { + if (!state.needsHover) { + return; + } + const devicePixelRatio = window.devicePixelRatio || 1; + state.pickingX = Math.floor(selection.x * devicePixelRatio); + state.pickingY = Math.floor(selection.y * devicePixelRatio); + state.triggerSelection = true; + hover = true; + }); + listenForRedraw(uiModel.moveSelection); + + const selectionCallback = (selectionInfo) => { + // Advanced picking and moving code from gltfx +/* if (state.highlightedNodes[0] === selectionInfo.node) { + return; + } + if (selectionInfo.node === undefined) { + state.highlightedNodes = []; + } else if (hover && !select && state.highlightedNodes.length > 0) { + const node = state.highlightedNodes[0]; + let targetNode = selectionInfo.node; + while (targetNode.parentNode !== undefined && targetNode.extras?.asset === undefined) { + targetNode = targetNode.parentNode; + } + if (targetNode.extras?.asset !== undefined) { + selectionInfo.node = targetNode; + } + // Change parent + if (selectionInfo.node !== node.parentNode) { + selectionInfo.node.children.push(node.jsonArrayIndex); + if (node.parentNode !== undefined) { + const childIndex = node.parentNode.children.indexOf(node.jsonArrayIndex); + node.parentNode.children.splice(childIndex, 1); + node.parentNode.changed = true; + } else { + const currentScene = state.gltf.scenes[state.sceneIndex]; + const childIndex = currentScene.nodes.indexOf(node.jsonArrayIndex); + currentScene.nodes.splice(childIndex, 1); + } + node.parentNode = selectionInfo.node; + selectionInfo.node.changed = true; + } + + // Rotate onto normal + const constUp = vec3.fromValues(0, 1, 0); + const normal = selectionInfo.normal; + vec3.normalize(normal, normal); + const angle = vec3.angle(constUp, normal); + const axis = vec3.cross(vec3.create(), constUp, normal); + vec3.normalize(axis, axis); + const rotation = quat.create(); + + + // Handle 180 degree rotations + if (vec3.length(axis) < 0.0001 && angle > 3.14) { + quat.setAxisAngle(rotation, vec3.fromValues(1, 0, 0), angle); + } else { + quat.setAxisAngle(rotation, axis, angle); + } + quat.normalize(rotation, rotation); + + const globalMatrix = mat4.fromRotationTranslation(mat4.create(), rotation, selectionInfo.position); + + // Add rotation around up from model + const rotationMatrix = mat4.fromQuat(mat4.create(), node.initialRotation); + mat4.multiply(globalMatrix, globalMatrix, rotationMatrix); + + const parentInverseGlobalTransform = node.parentNode?.inverseWorldTransform ?? mat4.create(); + const localMatrix = mat4.multiply(mat4.create(), parentInverseGlobalTransform, globalMatrix); + node.rotation = mat4.getRotation(quat.create(), localMatrix); + node.translation = mat4.getTranslation(vec3.create(), localMatrix); + node.scale = mat4.getScaling(vec3.create(), localMatrix); + + node.changed = true; + hover = false; + update(); + } else if (select) { + let assetNode = selectionInfo.node; + while (assetNode.parentNode !== undefined && assetNode.extras?.asset === undefined) { + assetNode = assetNode.parentNode; + } + if (assetNode.extras?.asset !== undefined) { + selectionInfo.node = assetNode; + } + const selection = [selectionInfo.node]; + const getAllChildren = (node) => { + if (node.children !== undefined) { + for (const childIdx of node.children) { + const child = state.gltf.nodes[childIdx]; + selection.push(child); + getAllChildren(child); + } + } + }; + // Select all child nodes + getAllChildren(selectionInfo.node); + + state.highlightedNodes = selection; + select = false; + } + redraw = true; */ + }; + + state.selectionCallback = selectionCallback; + + // configure the animation loop const past = {}; const update = () => { @@ -576,8 +695,8 @@ export default async () => { past.height = canvas.height; if (redraw) { - view.renderFrame(state, canvas.width, canvas.height); redraw = false; + view.renderFrame(state, canvas.width, canvas.height); } window.requestAnimationFrame(update); diff --git a/src/ui/sass.scss b/src/ui/sass.scss index 4b200305..2d99befc 100644 --- a/src/ui/sass.scss +++ b/src/ui/sass.scss @@ -349,6 +349,10 @@ button.button -moz-user-select: none; } +#canvasUI { + position:relative; +} + .canvasUIMaximize { left: 25px; bottom: 25px; From 6474ed205387065228e6dc2df4f718f570aa3168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Mon, 1 Sep 2025 18:20:27 +0200 Subject: [PATCH 27/41] Update Readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d253e195..0b456206 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,11 @@ Features ### glTF - [x] glTF 2.0 +- [KHR_accessor_float64](https://github.com/KhronosGroup/glTF/pull/2397) + - [x] Animations + - [x] KHR_animation_pointer + - [ ] Mesh Attributes not supported since WebGL2 only supports 32 bit + - [ ] Skins not supported since WebGL2 only supports 32 bit - [x] [KHR_animation_pointer](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer) - [x] [KHR_draco_mesh_compression](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_draco_mesh_compression) - [x] [KHR_lights_punctual](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual) From 7223a3d0988a9b21d9fd1626b3ddb99202e084bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Mon, 1 Sep 2025 18:21:23 +0200 Subject: [PATCH 28/41] Rework reset --- glTF-Sample-Renderer | 2 +- package-lock.json | 10 +++++----- src/main.js | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 81769f8c..8856eb88 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 81769f8c0f24671a19155697765f44a05f0280d4 +Subproject commit 8856eb8841218ddc68a1b9d85db5488f7228a227 diff --git a/package-lock.json b/package-lock.json index 5706ced5..c37a96cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ } }, "../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine": { - "name": "khr_interactivity_authoring_engine", + "name": "@khronosgroup/khr-interactivity-authoring-engine", "version": "0.1.0", "license": "Apache-2.0", "dependencies": { @@ -62,7 +62,7 @@ "version": "1.1.0", "license": "Apache-2.0", "dependencies": { - "@khronosgroup/khr_interactivity_authoring_engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "@khronosgroup/khr-interactivity-authoring-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "fast-png": "^6.2.0", "gl-matrix": "^3.2.1", "globals": "^15.5.0", @@ -1124,7 +1124,7 @@ "resolved": "glTF-Sample-Renderer", "link": true }, - "node_modules/@khronosgroup/khr_interactivity_authoring_engine": { + "node_modules/@khronosgroup/khr-interactivity-authoring-engine": { "resolved": "../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "link": true }, @@ -5762,7 +5762,7 @@ "@khronosgroup/gltf-viewer": { "version": "file:glTF-Sample-Renderer", "requires": { - "@khronosgroup/khr_interactivity_authoring_engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "@khronosgroup/khr-interactivity-authoring-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-wasm": "^6.2.2", @@ -6322,7 +6322,7 @@ } } }, - "@khronosgroup/khr_interactivity_authoring_engine": { + "@khronosgroup/khr-interactivity-authoring-engine": { "version": "file:../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "requires": { "@types/node": "^24.1.0", diff --git a/src/main.js b/src/main.js index 512684a9..3a47f4c4 100644 --- a/src/main.js +++ b/src/main.js @@ -163,6 +163,7 @@ export default async () => { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); + state.graphController.resumeGraph(); } else { state.graphController.stopGraphEngine(); } From 58aec463340ae6b402f856f2ebe425e972540245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Tue, 2 Sep 2025 16:09:43 +0200 Subject: [PATCH 29/41] Add KHR_node_visibility support --- README.md | 1 + glTF-Sample-Renderer | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b456206..6f3d2bbb 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Features - [x] [KHR_materials_variants](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_variants) - [x] [KHR_materials_volume](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_volume) - [x] [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_mesh_quantization) +- [x] [KHR_node_visibility](https://github.com/KhronosGroup/glTF/pull/2410) - [x] [KHR_texture_basisu](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_basisu) - [x] [KHR_texture_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) - [x] [KHR_xmp_json_ld](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_xmp_json_ld) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 8856eb88..9cd9730c 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 8856eb8841218ddc68a1b9d85db5488f7228a227 +Subproject commit 9cd9730ca729dbecd26d021ed6b23a05e4f71ae4 From 6887dad18666226fdd78ecba2c2fbce5eb21184f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 18 Sep 2025 10:44:42 +0200 Subject: [PATCH 30/41] Clean up selection/hover --- glTF-Sample-Renderer | 2 +- src/main.js | 101 +------------------------------------------ 2 files changed, 2 insertions(+), 101 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 9cd9730c..191e46f9 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 9cd9730ca729dbecd26d021ed6b23a05e4f71ae4 +Subproject commit 191e46f96e09b2460aae02947f980f9bb1b9bba6 diff --git a/src/main.js b/src/main.js index 3a47f4c4..dd624dbf 100644 --- a/src/main.js +++ b/src/main.js @@ -553,123 +553,24 @@ export default async () => { listenForRedraw(gltfLoaded); - let select = false; uiModel.selection.subscribe(selection => { const devicePixelRatio = window.devicePixelRatio || 1; state.pickingX = Math.floor(selection.x * devicePixelRatio); state.pickingY = Math.floor(selection.y * devicePixelRatio); state.triggerSelection = true; - select = true; }); listenForRedraw(uiModel.selection); - let hover = false; uiModel.moveSelection.subscribe(selection => { - if (!state.needsHover) { + if (!state.enableHover) { return; } const devicePixelRatio = window.devicePixelRatio || 1; state.pickingX = Math.floor(selection.x * devicePixelRatio); state.pickingY = Math.floor(selection.y * devicePixelRatio); - state.triggerSelection = true; - hover = true; }); listenForRedraw(uiModel.moveSelection); - const selectionCallback = (selectionInfo) => { - // Advanced picking and moving code from gltfx -/* if (state.highlightedNodes[0] === selectionInfo.node) { - return; - } - if (selectionInfo.node === undefined) { - state.highlightedNodes = []; - } else if (hover && !select && state.highlightedNodes.length > 0) { - const node = state.highlightedNodes[0]; - let targetNode = selectionInfo.node; - while (targetNode.parentNode !== undefined && targetNode.extras?.asset === undefined) { - targetNode = targetNode.parentNode; - } - if (targetNode.extras?.asset !== undefined) { - selectionInfo.node = targetNode; - } - // Change parent - if (selectionInfo.node !== node.parentNode) { - selectionInfo.node.children.push(node.jsonArrayIndex); - if (node.parentNode !== undefined) { - const childIndex = node.parentNode.children.indexOf(node.jsonArrayIndex); - node.parentNode.children.splice(childIndex, 1); - node.parentNode.changed = true; - } else { - const currentScene = state.gltf.scenes[state.sceneIndex]; - const childIndex = currentScene.nodes.indexOf(node.jsonArrayIndex); - currentScene.nodes.splice(childIndex, 1); - } - node.parentNode = selectionInfo.node; - selectionInfo.node.changed = true; - } - - // Rotate onto normal - const constUp = vec3.fromValues(0, 1, 0); - const normal = selectionInfo.normal; - vec3.normalize(normal, normal); - const angle = vec3.angle(constUp, normal); - const axis = vec3.cross(vec3.create(), constUp, normal); - vec3.normalize(axis, axis); - const rotation = quat.create(); - - - // Handle 180 degree rotations - if (vec3.length(axis) < 0.0001 && angle > 3.14) { - quat.setAxisAngle(rotation, vec3.fromValues(1, 0, 0), angle); - } else { - quat.setAxisAngle(rotation, axis, angle); - } - quat.normalize(rotation, rotation); - - const globalMatrix = mat4.fromRotationTranslation(mat4.create(), rotation, selectionInfo.position); - - // Add rotation around up from model - const rotationMatrix = mat4.fromQuat(mat4.create(), node.initialRotation); - mat4.multiply(globalMatrix, globalMatrix, rotationMatrix); - - const parentInverseGlobalTransform = node.parentNode?.inverseWorldTransform ?? mat4.create(); - const localMatrix = mat4.multiply(mat4.create(), parentInverseGlobalTransform, globalMatrix); - node.rotation = mat4.getRotation(quat.create(), localMatrix); - node.translation = mat4.getTranslation(vec3.create(), localMatrix); - node.scale = mat4.getScaling(vec3.create(), localMatrix); - - node.changed = true; - hover = false; - update(); - } else if (select) { - let assetNode = selectionInfo.node; - while (assetNode.parentNode !== undefined && assetNode.extras?.asset === undefined) { - assetNode = assetNode.parentNode; - } - if (assetNode.extras?.asset !== undefined) { - selectionInfo.node = assetNode; - } - const selection = [selectionInfo.node]; - const getAllChildren = (node) => { - if (node.children !== undefined) { - for (const childIdx of node.children) { - const child = state.gltf.nodes[childIdx]; - selection.push(child); - getAllChildren(child); - } - } - }; - // Select all child nodes - getAllChildren(selectionInfo.node); - - state.highlightedNodes = selection; - select = false; - } - redraw = true; */ - }; - - state.selectionCallback = selectionCallback; - // configure the animation loop const past = {}; From 7f96b01f518de4bbf010cd46183821b6467b718e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 16 Oct 2025 19:01:39 +0200 Subject: [PATCH 31/41] Add interactivity test feedback to frontend --- glTF-Sample-Renderer | 2 +- src/main.js | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 191e46f9..061f0c32 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 191e46f96e09b2460aae02947f980f9bb1b9bba6 +Subproject commit 061f0c3264f1a207998b83f424d20ce36efe73e6 diff --git a/src/main.js b/src/main.js index dd624dbf..a3b71720 100644 --- a/src/main.js +++ b/src/main.js @@ -2,7 +2,7 @@ import { GltfView } from "@khronosgroup/gltf-viewer"; import { UIModel } from "./logic/uimodel.js"; import { app } from "./ui/ui.js"; -import { EMPTY, from, merge, of } from "rxjs"; +import { EMPTY, from, merge } from "rxjs"; import { mergeMap, map, share, catchError } from "rxjs/operators"; import { GltfModelPathProvider, @@ -10,7 +10,6 @@ import { } from "./model_path_provider.js"; import {validateBytes} from "gltf-validator"; -import { mat4, quat, vec3 } from 'gl-matrix'; export default async () => { const canvas = document.getElementById("canvas"); @@ -23,6 +22,21 @@ export default async () => { const state = view.createState(); state.renderingParameters.useDirectionalLightsWithDisabledIBL = true; + state.graphController.addCustomEventListener("test/onStart", (event) => { + console.log("Test duration: ", event); + }); + state.graphController.addCustomEventListener("test/onSuccess", () => { + const message = "Interactivity test succeeded"; + console.log(message); + app.$buefy.toast.open({ + message: message, + type: 'is-success' + }); + }); + state.graphController.addCustomEventListener("test/onFail", () => { + const message = "Interactivity test failed"; + console.error(message); + }); const pathProvider = new GltfModelPathProvider( "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main" ); From a34b6696e5fe36eb8fe850d0536527964cd863bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 17 Oct 2025 11:47:24 +0200 Subject: [PATCH 32/41] Handle moving the mouse outside the window for hover --- src/logic/uimodel.js | 6 +++++- src/main.js | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index a51dfe56..fd455ab8 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -383,7 +383,7 @@ const getInputObservables = (inputElement, app) => { map(file => ({hdr_path: file})) ); - const mouseMove = fromEvent(document, 'mousemove'); + const mouseMove = merge(fromEvent(inputElement, 'mousemove'), fromEvent(inputElement, 'mouseout')); const mouseDown = fromEvent(inputElement, 'mousedown'); const mouseUp = merge(fromEvent(document, 'mouseup'), fromEvent(document, 'mouseleave')); const click = fromEvent(inputElement, 'click'); @@ -393,6 +393,7 @@ const getInputObservables = (inputElement, app) => { inputElement.addEventListener('mouseup', event => event.preventDefault()); inputElement.addEventListener('dblclick', event => event.preventDefault()); inputElement.addEventListener('click', event => event.preventDefault()); + inputElement.addEventListener('mouseout', event => event.preventDefault()); const selection = click.pipe( filter(event => event.button === 0), @@ -402,6 +403,9 @@ const getInputObservables = (inputElement, app) => { const move = mouseMove.pipe( map((moveEvent) => { + if (moveEvent.type === 'mouseout') { + return {x: undefined, y: undefined}; + } return {x: moveEvent.pageX, y: moveEvent.pageY}; })); diff --git a/src/main.js b/src/main.js index a3b71720..edd44d10 100644 --- a/src/main.js +++ b/src/main.js @@ -579,6 +579,11 @@ export default async () => { if (!state.enableHover) { return; } + if (selection.x === undefined || selection.y === undefined) { + state.pickingX = undefined; + state.pickingY = undefined; + return; + } const devicePixelRatio = window.devicePixelRatio || 1; state.pickingX = Math.floor(selection.x * devicePixelRatio); state.pickingY = Math.floor(selection.y * devicePixelRatio); From 00baf419d4dc5d923f4ee86b3f506a18a3d017b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 17 Oct 2025 15:06:02 +0200 Subject: [PATCH 33/41] Fix event listener --- src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index edd44d10..dfebf71c 100644 --- a/src/main.js +++ b/src/main.js @@ -33,7 +33,7 @@ export default async () => { type: 'is-success' }); }); - state.graphController.addCustomEventListener("test/onFail", () => { + state.graphController.addCustomEventListener("test/onFailed", () => { const message = "Interactivity test failed"; console.error(message); }); From 41aebe666f39a61ce108e3296aecfb7bd3c5a3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Tue, 21 Oct 2025 16:45:04 +0200 Subject: [PATCH 34/41] Update submodule --- glTF-Sample-Renderer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 061f0c32..e2dfebed 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 061f0c3264f1a207998b83f424d20ce36efe73e6 +Subproject commit e2dfebed9e52c3b83105265958064ea6bd624e2f From 489421e4cd10bc5d83d3e82a89ee0662131b4aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Tue, 21 Oct 2025 17:16:26 +0200 Subject: [PATCH 35/41] Fix formatting --- eslint.config.js | 6 +- glTF-Sample-Renderer | 2 +- package-lock.json | 299 +++++++++++++++++++++++++++---------------- src/logic/uimodel.js | 63 +++++---- src/main.js | 58 ++++----- src/ui/ui.js | 94 ++++++++------ 6 files changed, 313 insertions(+), 209 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 4f7a2613..b5b27081 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -24,7 +24,11 @@ export default [ "semi": "warn", "no-extra-semi": "warn", "no-undef": "warn", - "no-unused-vars": "warn", + "no-unused-vars": ["warn", + { + "argsIgnorePattern": "^_", + } + ], "no-empty": "warn", "no-redeclare": "warn", "no-prototype-builtins": "warn", diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index e2dfebed..17ad0c99 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit e2dfebed9e52c3b83105265958064ea6bd624e2f +Subproject commit 17ad0c99dfcbbbf7828ef813b2b5d2dc35a825f0 diff --git a/package-lock.json b/package-lock.json index d9388b0f..3224e433 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,9 +72,11 @@ "json-ptr": "^3.1.0" }, "devDependencies": { + "@playwright/test": "^1.56.0", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-wasm": "^6.2.2", + "@types/node": "^24.7.2", "concurrently": "^8.2.2", "eslint": "^9.5.0", "eslint-config-prettier": "^10.1.8", @@ -84,7 +86,7 @@ "rollup-plugin-copy": "^3.5.0", "rollup-plugin-glslify": "^1.3.1", "rollup-plugin-license": "^3.5.2", - "serve": "^14.2.4" + "serve": "^14.2.5" } }, "glTF-Sample-Renderer/node_modules/@jsdoc/salty": { @@ -1180,6 +1182,21 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", + "dev": true, + "dependencies": { + "playwright": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@rollup/plugin-commonjs": { "version": "26.0.3", "dev": true, @@ -1556,11 +1573,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.4", + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "dev": true, - "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~7.16.0" } }, "node_modules/@types/pako": { @@ -1660,19 +1678,6 @@ "integrity": "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==", "dev": true }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.12.1", "dev": true, @@ -2191,23 +2196,32 @@ } }, "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/compression/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2223,6 +2237,26 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/concat-map": { "version": "0.0.1", "dev": true, @@ -3831,27 +3865,6 @@ "node": ">= 0.6" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -3928,9 +3941,9 @@ "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true, "engines": { "node": ">= 0.6" @@ -4030,9 +4043,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true, "engines": { "node": ">= 0.8" @@ -4242,6 +4255,50 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "dev": true, + "dependencies": { + "playwright-core": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/portfinder": { "version": "1.0.32", "dev": true, @@ -4824,9 +4881,9 @@ } }, "node_modules/serve": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.4.tgz", - "integrity": "sha512-qy1S34PJ/fcY8gjVGszDB3EXiPSk5FKhUa7tQe0UPRddxRidc2V6cNHPNewbE1D7MAkgLuWEt3Vw56vYy73tzQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.5.tgz", + "integrity": "sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==", "dev": true, "dependencies": { "@zeit/schemas": "2.36.0", @@ -4836,7 +4893,7 @@ "chalk": "5.0.1", "chalk-template": "0.4.0", "clipboardy": "3.0.0", - "compression": "1.7.4", + "compression": "1.8.1", "is-port-reachable": "4.0.0", "serve-handler": "6.1.6", "update-check": "1.5.4" @@ -5345,9 +5402,10 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "6.19.8", - "dev": true, - "license": "MIT" + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true }, "node_modules/union": { "version": "0.5.0", @@ -5799,9 +5857,11 @@ "version": "file:glTF-Sample-Renderer", "requires": { "@khronosgroup/khr-interactivity-authoring-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "@playwright/test": "^1.56.0", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-wasm": "^6.2.2", + "@types/node": "^24.7.2", "concurrently": "^8.2.2", "eslint": "^9.5.0", "eslint-config-prettier": "^10.1.8", @@ -5816,7 +5876,7 @@ "rollup-plugin-copy": "^3.5.0", "rollup-plugin-glslify": "^1.3.1", "rollup-plugin-license": "^3.5.2", - "serve": "^14.2.4" + "serve": "^14.2.5" }, "dependencies": { "@jsdoc/salty": { @@ -6397,6 +6457,15 @@ "dev": true, "optional": true }, + "@playwright/test": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", + "dev": true, + "requires": { + "playwright": "1.56.1" + } + }, "@rollup/plugin-commonjs": { "version": "26.0.3", "dev": true, @@ -6591,10 +6660,12 @@ "dev": true }, "@types/node": { - "version": "22.7.4", + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "dev": true, "requires": { - "undici-types": "~6.19.2" + "undici-types": "~7.16.0" } }, "@types/pako": { @@ -6680,16 +6751,6 @@ "integrity": "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==", "dev": true }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, "acorn": { "version": "8.12.1", "dev": true @@ -7031,20 +7092,26 @@ } }, "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7059,6 +7126,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true } } }, @@ -8129,23 +8202,6 @@ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - } - } - }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -8187,9 +8243,9 @@ "dev": true }, "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true }, "nodemon": { @@ -8250,9 +8306,9 @@ "dev": true }, "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true }, "once": { @@ -8380,6 +8436,31 @@ "version": "2.3.1", "dev": true }, + "playwright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.56.1" + }, + "dependencies": { + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + } + } + }, + "playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "dev": true + }, "portfinder": { "version": "1.0.32", "dev": true, @@ -8735,9 +8816,9 @@ "dev": true }, "serve": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.4.tgz", - "integrity": "sha512-qy1S34PJ/fcY8gjVGszDB3EXiPSk5FKhUa7tQe0UPRddxRidc2V6cNHPNewbE1D7MAkgLuWEt3Vw56vYy73tzQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.5.tgz", + "integrity": "sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==", "dev": true, "requires": { "@zeit/schemas": "2.36.0", @@ -8747,7 +8828,7 @@ "chalk": "5.0.1", "chalk-template": "0.4.0", "clipboardy": "3.0.0", - "compression": "1.7.4", + "compression": "1.8.1", "is-port-reachable": "4.0.0", "serve-handler": "6.1.6", "update-check": "1.5.4" @@ -9088,7 +9169,9 @@ "dev": true }, "undici-types": { - "version": "6.19.8", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true }, "union": { diff --git a/src/logic/uimodel.js b/src/logic/uimodel.js index e27c6178..ac9bb940 100644 --- a/src/logic/uimodel.js +++ b/src/logic/uimodel.js @@ -240,7 +240,12 @@ class UIModel { this.app.graphState = true; if (gltf && gltf?.extensions?.KHR_materials_variants?.variants !== undefined) { - this.app.materialVariants = ["None", ...gltf.extensions.KHR_materials_variants.variants.map(variant => variant?.name ?? "Unnamed")]; + this.app.materialVariants = [ + "None", + ...gltf.extensions.KHR_materials_variants.variants.map( + (variant) => variant?.name ?? "Unnamed" + ) + ]; } else { this.app.materialVariants = ["None"]; } @@ -250,7 +255,10 @@ class UIModel { })); // Set up interactivity graphs if available - if (gltf?.extensions?.KHR_interactivity?.graphs !== undefined && state.renderingParameters.enabledExtensions.KHR_interactivity) { + if ( + gltf?.extensions?.KHR_interactivity?.graphs !== undefined && + state.renderingParameters.enabledExtensions.KHR_interactivity + ) { this.app.graphs = gltf.extensions.KHR_interactivity.graphs.map((graph, index) => ({ title: graph.name ?? `Graph ${index}`, index: index @@ -262,7 +270,10 @@ class UIModel { this.app.customEvents = []; } - this.app.xmp = gltf?.extensions?.KHR_xmp_json_ld?.packets[gltf?.asset?.extensions?.KHR_xmp_json_ld.packet] ?? null; + this.app.xmp = + gltf?.extensions?.KHR_xmp_json_ld?.packets[ + gltf?.asset?.extensions?.KHR_xmp_json_ld.packet + ] ?? null; }); } @@ -414,10 +425,7 @@ const getInputObservables = (inputElement, app) => { additionalFiles = additionalFiles.map((file) => { let filePath = file[0].replaceAll("\\", "/"); if (filePath.startsWith(folderPath)) { - return [ - filePath.substr(folderPath.length), - file[1] - ]; + return [filePath.substr(folderPath.length), file[1]]; } else { return file; } @@ -440,31 +448,36 @@ const getInputObservables = (inputElement, app) => { map((file) => ({ hdr_path: file })) ); - const mouseMove = merge(fromEvent(inputElement, 'mousemove'), fromEvent(inputElement, 'mouseout')); - const mouseDown = fromEvent(inputElement, 'mousedown'); - const mouseUp = merge(fromEvent(document, 'mouseup'), fromEvent(document, 'mouseleave')); - const click = fromEvent(inputElement, 'click'); - - inputElement.addEventListener('mousemove', event => event.preventDefault()); - inputElement.addEventListener('mousedown', event => event.preventDefault()); - inputElement.addEventListener('mouseup', event => event.preventDefault()); - inputElement.addEventListener('dblclick', event => event.preventDefault()); - inputElement.addEventListener('click', event => event.preventDefault()); - inputElement.addEventListener('mouseout', event => event.preventDefault()); + const mouseMove = merge( + fromEvent(inputElement, "mousemove"), + fromEvent(inputElement, "mouseout") + ); + const mouseDown = fromEvent(inputElement, "mousedown"); + const mouseUp = merge(fromEvent(document, "mouseup"), fromEvent(document, "mouseleave")); + const click = fromEvent(inputElement, "click"); + + inputElement.addEventListener("mousemove", (event) => event.preventDefault()); + inputElement.addEventListener("mousedown", (event) => event.preventDefault()); + inputElement.addEventListener("mouseup", (event) => event.preventDefault()); + inputElement.addEventListener("dblclick", (event) => event.preventDefault()); + inputElement.addEventListener("click", (event) => event.preventDefault()); + inputElement.addEventListener("mouseout", (event) => event.preventDefault()); const selection = click.pipe( - filter(event => event.button === 0), + filter((event) => event.button === 0), map((clickEvent) => { - return {x: clickEvent.pageX, y: clickEvent.pageY}; - })); + return { x: clickEvent.pageX, y: clickEvent.pageY }; + }) + ); const move = mouseMove.pipe( map((moveEvent) => { - if (moveEvent.type === 'mouseout') { - return {x: undefined, y: undefined}; + if (moveEvent.type === "mouseout") { + return { x: undefined, y: undefined }; } - return {x: moveEvent.pageX, y: moveEvent.pageY}; - })); + return { x: moveEvent.pageX, y: moveEvent.pageY }; + }) + ); const mouseOrbit = mouseDown.pipe( filter((event) => event.button === 0 && event.shiftKey === false), diff --git a/src/main.js b/src/main.js index eb0c3462..408bf8d7 100644 --- a/src/main.js +++ b/src/main.js @@ -27,7 +27,7 @@ export default async () => { console.log(message); app.$buefy.toast.open({ message: message, - type: 'is-success' + type: "is-success" }); }); state.graphController.addCustomEventListener("test/onFailed", () => { @@ -185,7 +185,8 @@ export default async () => { state.animationTimer.start(); if (state.gltf?.extensions?.KHR_interactivity?.graphs !== undefined) { state.graphController.initializeGraphs(state); - const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; + const graphIndex = + state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.startGraph(graphIndex); state.graphController.resumeGraph(); } else { @@ -313,22 +314,19 @@ export default async () => { ); listenForRedraw(uiModel.morphingEnabled); - uiModel.interactivityEnabled.subscribe( - (interactivityEnabled) => - { - state.renderingParameters.enabledExtensions.KHR_interactivity = interactivityEnabled; - if (state.gltf?.extensions?.KHR_interactivity === undefined) { - return; - } - if (interactivityEnabled) { - state.graphController.initializeGraphs(state); - const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; - state.graphController.startGraph(graphIndex); - } else { - state.graphController.stopGraphEngine(); - } + uiModel.interactivityEnabled.subscribe((interactivityEnabled) => { + state.renderingParameters.enabledExtensions.KHR_interactivity = interactivityEnabled; + if (state.gltf?.extensions?.KHR_interactivity === undefined) { + return; } - ); + if (interactivityEnabled) { + state.graphController.initializeGraphs(state); + const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; + state.graphController.startGraph(graphIndex); + } else { + state.graphController.stopGraphEngine(); + } + }); listenForRedraw(uiModel.interactivityEnabled); uiModel.clearcoatEnabled.subscribe( @@ -404,33 +402,31 @@ export default async () => { uiModel.volumeScatteringEnabled.subscribe( (enabled) => (state.renderingParameters.enabledExtensions.KHR_materials_volume_scatter = enabled) - ); - listenForRedraw(uiModel.volumeScatteringEnabled); - + ); + listenForRedraw(uiModel.volumeScatteringEnabled); + uiModel.hoverabilityEnabled.subscribe( (hoverabilityEnabled) => (state.renderingParameters.enabledExtensions.KHR_node_hoverability = - hoverabilityEnabled) + hoverabilityEnabled) ); listenForRedraw(uiModel.hoverabilityEnabled); uiModel.selectabilityEnabled.subscribe( (selectabilityEnabled) => (state.renderingParameters.enabledExtensions.KHR_node_selectability = - selectabilityEnabled) + selectabilityEnabled) ); listenForRedraw(uiModel.selectabilityEnabled); uiModel.nodeVisibilityEnabled.subscribe( (nodeVisibilityEnabled) => (state.renderingParameters.enabledExtensions.KHR_node_visibility = - nodeVisibilityEnabled) + nodeVisibilityEnabled) ); listenForRedraw(uiModel.nodeVisibilityEnabled); - uiModel.iblEnabled.subscribe( - (iblEnabled) => (state.renderingParameters.useIBL = iblEnabled) - ); + uiModel.iblEnabled.subscribe((iblEnabled) => (state.renderingParameters.useIBL = iblEnabled)); listenForRedraw(uiModel.iblEnabled); uiModel.iblIntensity.subscribe( @@ -504,9 +500,7 @@ export default async () => { redraw = true; }); - uiModel.activeAnimations.subscribe( - (animations) => (state.animationIndices = animations) - ); + uiModel.activeAnimations.subscribe((animations) => (state.animationIndices = animations)); listenForRedraw(uiModel.activeAnimations); uiModel.selectedGraph.subscribe((graphIndex) => { @@ -520,7 +514,6 @@ export default async () => { const values = {}; for (const key in eventData.values) { values[key] = eventData.values[key]; - } state.graphController.dispatchEvent(eventData.eventId, values); } @@ -563,7 +556,7 @@ export default async () => { listenForRedraw(gltfLoaded); - uiModel.selection.subscribe(selection => { + uiModel.selection.subscribe((selection) => { const devicePixelRatio = window.devicePixelRatio || 1; state.pickingX = Math.floor(selection.x * devicePixelRatio); state.pickingY = Math.floor(selection.y * devicePixelRatio); @@ -571,7 +564,7 @@ export default async () => { }); listenForRedraw(uiModel.selection); - uiModel.moveSelection.subscribe(selection => { + uiModel.moveSelection.subscribe((selection) => { if (!state.enableHover) { return; } @@ -586,7 +579,6 @@ export default async () => { }); listenForRedraw(uiModel.moveSelection); - // configure the animation loop const past = {}; const update = () => { diff --git a/src/ui/ui.js b/src/ui/ui.js index 2aa42cc8..048f4f94 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -11,7 +11,7 @@ const appCreated = createApp({ sceneChanged: new Subject(), cameraChanged: new Subject(), selectedGraphChanged: new Subject(), - + debugchannelChanged: new Subject(), tonemapChanged: new Subject(), skinningChanged: new Subject(), @@ -72,11 +72,11 @@ const appCreated = createApp({ cameras: [{ title: "User Camera", index: -1 }], materialVariants: ["None"], - animations: [{title: "None"}], + animations: [{ title: "None" }], graphs: [], - tonemaps: [{title: "None"}], - debugchannels: [{title: "None"}], - xmp: [{title: "xmp"}], + tonemaps: [{ title: "None" }], + debugchannels: [{ title: "None" }], + xmp: [{ title: "xmp" }], assetCopyright: "", assetGenerator: "", statistics: [], @@ -153,7 +153,7 @@ const appCreated = createApp({ customEventFocusedInput: null, customEventFocusedIndex: null, customEventValid: true, - customEventSendClicked: new Subject(), + customEventSendClicked: new Subject() }; }, watch: { @@ -266,14 +266,14 @@ const appCreated = createApp({ }, currentCustomEvent() { if (!this.selectedCustomEvent || !this.customEvents) return null; - return this.customEvents.find(event => event.id === this.selectedCustomEvent); + return this.customEvents.find((event) => event.id === this.selectedCustomEvent); }, customEventInputs() { if (!this.currentCustomEvent) return []; const event = this.currentCustomEvent; if (!event.values) return []; - - return Object.keys(event.values).map(key => ({ + + return Object.keys(event.values).map((key) => ({ name: key, type: event.values[key].type, value: event.values[key].value @@ -389,9 +389,8 @@ const appCreated = createApp({ `

` ); }, - iblTriggered: function(value) - { - if(value == false) { + iblTriggered: function (value) { + if (value == false) { this.environmentVisiblePrefState = this.renderEnv; this.renderEnv = false; this.renderEnvChanged.next(false); @@ -484,52 +483,65 @@ const appCreated = createApp({ this.customEventValues = {}; return; } - - const event = this.customEvents.find(e => e.id === selectedEventId); + + const event = this.customEvents.find((e) => e.id === selectedEventId); if (!event || !event.values) { this.customEventValues = {}; return; } - + // Initialize all input values based on the event definition const values = {}; - Object.keys(event.values).forEach(key => { + Object.keys(event.values).forEach((key) => { const valueDefn = event.values[key]; - values[key] = valueDefn.value !== undefined ? valueDefn.value : this.getDefaultValue(valueDefn.type); + values[key] = + valueDefn.value !== undefined + ? valueDefn.value + : this.getDefaultValue(valueDefn.type); }); this.customEventValues = values; }, getDefaultValue(type) { - switch(type) { - case 'bool': return false; - case 'int': return 0; - case 'float': return 0.0; - case 'float2': return [0, 0]; - case 'float3': return [0, 0, 0]; - case 'float4': return [0, 0, 0, 0]; - case 'float2x2': return [1, 0, 0, 1]; - case 'float3x3': return [1, 0, 0, 0, 1, 0, 0, 0, 1]; - case 'float4x4': return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; - default: return null; + switch (type) { + case "bool": + return false; + case "int": + return 0; + case "float": + return 0.0; + case "float2": + return [0, 0]; + case "float3": + return [0, 0, 0]; + case "float4": + return [0, 0, 0, 0]; + case "float2x2": + return [1, 0, 0, 1]; + case "float3x3": + return [1, 0, 0, 0, 1, 0, 0, 0, 1]; + case "float4x4": + return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + default: + return null; } }, sendCustomEvent() { if (!this.selectedCustomEvent || !this.currentCustomEvent) { this.$buefy.toast.open({ - message: 'Please select a custom event first', - type: 'is-warning', + message: "Please select a custom event first", + type: "is-warning", duration: 3000 }); return; } - + this.customEventSendClicked.next({ eventId: this.selectedCustomEvent, values: this.customEventValues }); this.$buefy.toast.open({ message: `Custom event '${this.selectedCustomEvent}' sent successfully!`, - type: 'is-success', + type: "is-success", duration: 3000 }); } @@ -539,17 +551,17 @@ const appCreated = createApp({ appCreated.use(Buefy); // general components -appCreated.component('toggle-button', { - props: ['ontext', 'offtext', 'btnClass', 'modelValue'], - emits: ['buttonclicked', 'update:modelValue'], - template:'#toggleButtonTemplate', - data(){ +appCreated.component("toggle-button", { + props: ["ontext", "offtext", "btnClass", "modelValue"], + emits: ["buttonclicked", "update:modelValue"], + template: "#toggleButtonTemplate", + data() { return { name: "Play", isOn: false }; }, - mounted(){ + mounted() { this.name = this.offtext; // Initialize state from modelValue prop if provided if (this.modelValue !== undefined) { @@ -570,13 +582,13 @@ appCreated.component('toggle-button', { buttonclicked: function () { this.isOn = !this.isOn; this.name = this.isOn ? this.ontext : this.offtext; - this.$emit('buttonclicked', this.isOn); - this.$emit('update:modelValue', this.isOn); + this.$emit("buttonclicked", this.isOn); + this.$emit("update:modelValue", this.isOn); }, setState: function (value) { this.isOn = value; this.name = this.isOn ? this.ontext : this.offtext; - this.$emit('update:modelValue', this.isOn); + this.$emit("update:modelValue", this.isOn); } } }); From 74091cd2ca61ca7f6d2fb6d93c4f2b45e145396b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 24 Oct 2025 18:06:44 +0200 Subject: [PATCH 36/41] Update Readme --- README.md | 13 ++++++++----- eslint.config.js | 7 ++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3f0dfd4b..6eb9c97a 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,19 @@ Link to the live [glTF 2.0 Sample Viewer](https://github.khronos.org/glTF-Sample - [x] glTF 2.0 - [KHR_accessor_float64](https://github.com/KhronosGroup/glTF/pull/2397) - - [x] Animations - - [x] KHR_animation_pointer - - [ ] Mesh Attributes not supported since WebGL2 only supports 32 bit - - [ ] Skins not supported since WebGL2 only supports 32 bit + - [x] Animations + - [x] KHR_animation_pointer + - [ ] Mesh Attributes not supported since WebGL2 only supports 32 bit + - [ ] Skins not supported since WebGL2 only supports 32 bit - [x] [KHR_animation_pointer](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer) - [x] [KHR_draco_mesh_compression](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_draco_mesh_compression) +- [x] [KHR_interactivity](https://github.com/KhronosGroup/glTF/pull/2293) - [x] [KHR_lights_punctual](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual) - [x] [KHR_materials_anisotropy](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy) - [x] [KHR_materials_clearcoat](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_clearcoat) - [x] [KHR_materials_diffuse_transmission](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_diffuse_transmission/README.md) - [x] [KHR_materials_dispersion](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_dispersion) -- [x] [KHR_materials_emissive_strength](https://github.com/KhronosGroup/glTF/tree/KHR_materials_emissive_strength/extensions/2.0/Khronos/KHR_materials_emissive_strength) +- [x] [KHR_materials_emissive_strength](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_emissive_strength) - [x] [KHR_materials_ior](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_ior) - [x] [KHR_materials_iridescence](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_iridescence) - [x] [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness) @@ -39,6 +40,8 @@ Link to the live [glTF 2.0 Sample Viewer](https://github.khronos.org/glTF-Sample - [x] For dense volumes using KHR_materials_diffuse_transmission - [ ] For sparse volumes using KHR_materials_transmission - [x] [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_mesh_quantization) +- [x] [KHR_node_hoverability](https://github.com/KhronosGroup/glTF/pull/2426) +- [x] [KHR_node_selectability](https://github.com/KhronosGroup/glTF/pull/2422) - [x] [KHR_node_visibility](https://github.com/KhronosGroup/glTF/pull/2410) - [x] [KHR_texture_basisu](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_basisu) - [x] [KHR_texture_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) diff --git a/eslint.config.js b/eslint.config.js index eff824a1..06476c19 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -23,9 +23,10 @@ export default [ semi: "warn", "no-extra-semi": "warn", "no-undef": "warn", - "no-unused-vars": ["warn", - { - "argsIgnorePattern": "^_", + "no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_" } ], "no-empty": "warn", From 28af0e389bc35f374179bb1bc81e128cb0ad2dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Fri, 24 Oct 2025 18:08:07 +0200 Subject: [PATCH 37/41] Apply changes to API --- glTF-Sample-Renderer | 2 +- src/main.js | 21 +++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 17ad0c99..744cbb87 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 17ad0c99dfcbbbf7828ef813b2b5d2dc35a825f0 +Subproject commit 744cbb87328ba32def1dbeb74a9aa1c5fe0cc858 diff --git a/src/main.js b/src/main.js index 075f884b..28521ce5 100644 --- a/src/main.js +++ b/src/main.js @@ -187,7 +187,7 @@ export default async () => { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; - state.graphController.startGraph(graphIndex); + state.graphController.loadGraph(graphIndex); state.graphController.resumeGraph(); } else { state.graphController.stopGraphEngine(); @@ -322,7 +322,7 @@ export default async () => { if (interactivityEnabled) { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; - state.graphController.startGraph(graphIndex); + state.graphController.loadGraph(graphIndex); } else { state.graphController.stopGraphEngine(); } @@ -505,7 +505,7 @@ export default async () => { uiModel.selectedGraph.subscribe((graphIndex) => { if (graphIndex !== null && graphIndex !== undefined) { - state.graphController.startGraph(graphIndex); + state.graphController.loadGraph(graphIndex); } }); @@ -558,24 +558,21 @@ export default async () => { uiModel.selection.subscribe((selection) => { const devicePixelRatio = window.devicePixelRatio || 1; - state.pickingX = Math.floor(selection.x * devicePixelRatio); - state.pickingY = Math.floor(selection.y * devicePixelRatio); + state.selectionPositions[0].x = Math.floor(selection.x * devicePixelRatio); + state.selectionPositions[0].y = Math.floor(selection.y * devicePixelRatio); state.triggerSelection = true; }); listenForRedraw(uiModel.selection); uiModel.moveSelection.subscribe((selection) => { - if (!state.enableHover) { - return; - } if (selection.x === undefined || selection.y === undefined) { - state.pickingX = undefined; - state.pickingY = undefined; + state.hoverPositions[0].x = undefined; + state.hoverPositions[0].y = undefined; return; } const devicePixelRatio = window.devicePixelRatio || 1; - state.pickingX = Math.floor(selection.x * devicePixelRatio); - state.pickingY = Math.floor(selection.y * devicePixelRatio); + state.hoverPositions[0].x = Math.floor(selection.x * devicePixelRatio); + state.hoverPositions[0].y = Math.floor(selection.y * devicePixelRatio); }); listenForRedraw(uiModel.moveSelection); From 6e0f6b0e29a3c6e59cbc3dc8219e41a29b09839c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Tue, 28 Oct 2025 12:46:25 +0100 Subject: [PATCH 38/41] Update submodule --- .prettierignore | 3 ++- glTF-Sample-Renderer | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.prettierignore b/.prettierignore index 4ebfbfb1..5ea49dc4 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ -glTF-Sample-Renderer/source/libs \ No newline at end of file +glTF-Sample-Renderer/source/libs +**/*.md diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 744cbb87..3f05d6b1 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 744cbb87328ba32def1dbeb74a9aa1c5fe0cc858 +Subproject commit 3f05d6b103caf4f620e5fb2a0fa8d67d02410629 From f031874dfe1866324595113d6a4d947a0648985e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Wed, 29 Oct 2025 15:33:12 +0100 Subject: [PATCH 39/41] Subscribe to events after each reload --- glTF-Sample-Renderer | 2 +- src/main.js | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index 3f05d6b1..f2d615ed 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit 3f05d6b103caf4f620e5fb2a0fa8d67d02410629 +Subproject commit f2d615edf480c976916692eb9b5375a07c147aa9 diff --git a/src/main.js b/src/main.js index 28521ce5..3353c3cc 100644 --- a/src/main.js +++ b/src/main.js @@ -19,21 +19,6 @@ export default async () => { const state = view.createState(); state.renderingParameters.useDirectionalLightsWithDisabledIBL = true; - state.graphController.addCustomEventListener("test/onStart", (event) => { - console.log("Test duration: ", event); - }); - state.graphController.addCustomEventListener("test/onSuccess", () => { - const message = "Interactivity test succeeded"; - console.log(message); - app.$buefy.toast.open({ - message: message, - type: "is-success" - }); - }); - state.graphController.addCustomEventListener("test/onFailed", () => { - const message = "Interactivity test failed"; - console.error(message); - }); const pathProvider = new GltfModelPathProvider( "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main" ); @@ -185,6 +170,32 @@ export default async () => { state.animationTimer.start(); if (state.gltf?.extensions?.KHR_interactivity?.graphs !== undefined) { state.graphController.initializeGraphs(state); + + state.graphController.addCustomEventListener( + "test/onStart", + (event) => { + console.log("Test duration: ", event); + } + ); + state.graphController.addCustomEventListener( + "test/onSuccess", + () => { + const message = "Interactivity test succeeded"; + console.log(message); + app.$buefy.toast.open({ + message: message, + type: "is-success" + }); + } + ); + state.graphController.addCustomEventListener( + "test/onFailed", + () => { + const message = "Interactivity test failed"; + console.error(message); + } + ); + const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.loadGraph(graphIndex); From 676ed774df687b2d2a319fc381ac44768fd5546b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 30 Oct 2025 11:16:38 +0100 Subject: [PATCH 40/41] Revert "Subscribe to events after each reload" This reverts commit f031874dfe1866324595113d6a4d947a0648985e. --- src/main.js | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/main.js b/src/main.js index 3353c3cc..28521ce5 100644 --- a/src/main.js +++ b/src/main.js @@ -19,6 +19,21 @@ export default async () => { const state = view.createState(); state.renderingParameters.useDirectionalLightsWithDisabledIBL = true; + state.graphController.addCustomEventListener("test/onStart", (event) => { + console.log("Test duration: ", event); + }); + state.graphController.addCustomEventListener("test/onSuccess", () => { + const message = "Interactivity test succeeded"; + console.log(message); + app.$buefy.toast.open({ + message: message, + type: "is-success" + }); + }); + state.graphController.addCustomEventListener("test/onFailed", () => { + const message = "Interactivity test failed"; + console.error(message); + }); const pathProvider = new GltfModelPathProvider( "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main" ); @@ -170,32 +185,6 @@ export default async () => { state.animationTimer.start(); if (state.gltf?.extensions?.KHR_interactivity?.graphs !== undefined) { state.graphController.initializeGraphs(state); - - state.graphController.addCustomEventListener( - "test/onStart", - (event) => { - console.log("Test duration: ", event); - } - ); - state.graphController.addCustomEventListener( - "test/onSuccess", - () => { - const message = "Interactivity test succeeded"; - console.log(message); - app.$buefy.toast.open({ - message: message, - type: "is-success" - }); - } - ); - state.graphController.addCustomEventListener( - "test/onFailed", - () => { - const message = "Interactivity test failed"; - console.error(message); - } - ); - const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.loadGraph(graphIndex); From c19e6814c0be33a6e8895cd09212098bef727266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4rtl?= Date: Thu, 30 Oct 2025 11:56:08 +0100 Subject: [PATCH 41/41] Fix enable/disable extension behavior --- glTF-Sample-Renderer | 2 +- package-lock.json | 2389 ++++++++++++++++++------------------------ src/main.js | 12 + 3 files changed, 1035 insertions(+), 1368 deletions(-) diff --git a/glTF-Sample-Renderer b/glTF-Sample-Renderer index f2d615ed..7e5457e0 160000 --- a/glTF-Sample-Renderer +++ b/glTF-Sample-Renderer @@ -1 +1 @@ -Subproject commit f2d615edf480c976916692eb9b5375a07c147aa9 +Subproject commit 7e5457e0578c907ba8d63a8bd4a843f7b8594be5 diff --git a/package-lock.json b/package-lock.json index 3224e433..d4b9de47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ } }, "../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine": { - "name": "@khronosgroup/khr-interactivity-authoring-engine", + "name": "@khronosgroup/gltf-interactivity-sample-engine", "version": "0.1.0", "license": "Apache-2.0", "dependencies": { @@ -64,7 +64,7 @@ "version": "1.1.0", "license": "Apache-2.0", "dependencies": { - "@khronosgroup/khr-interactivity-authoring-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "@khronosgroup/gltf-interactivity-sample-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "fast-png": "^6.2.0", "gl-matrix": "^3.2.1", "globals": "^15.5.0", @@ -80,7 +80,7 @@ "concurrently": "^8.2.2", "eslint": "^9.5.0", "eslint-config-prettier": "^10.1.8", - "jsdoc-to-markdown": "^8.0.1", + "jsdoc-to-markdown": "^9.1.3", "prettier": "3.6.2", "rollup": "^4.23.0", "rollup-plugin-copy": "^3.5.0", @@ -89,801 +89,20 @@ "serve": "^14.2.5" } }, - "glTF-Sample-Renderer/node_modules/@jsdoc/salty": { - "version": "0.2.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v12.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/@types/linkify-it": { - "version": "5.0.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/@types/markdown-it": { - "version": "14.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" - } - }, - "glTF-Sample-Renderer/node_modules/@types/mdurl": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/ansi-escape-sequences": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/ansi-escape-sequences/node_modules/array-back": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "glTF-Sample-Renderer/node_modules/array-back": { - "version": "6.2.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.17" - } - }, - "glTF-Sample-Renderer/node_modules/bluebird": { - "version": "3.7.2", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/cache-point": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^4.0.1", - "fs-then-native": "^2.0.0", - "mkdirp2": "^1.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "glTF-Sample-Renderer/node_modules/cache-point/node_modules/array-back": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "glTF-Sample-Renderer/node_modules/catharsis": { - "version": "0.9.0", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.15" - }, - "engines": { - "node": ">= 10" - } - }, - "glTF-Sample-Renderer/node_modules/collect-all": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "stream-connect": "^1.0.2", - "stream-via": "^1.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-args": { - "version": "5.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-args/node_modules/array-back": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-args/node_modules/typical": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-tool": { - "version": "0.8.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "command-line-args": "^5.0.0", - "command-line-usage": "^4.1.0", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-tool/node_modules/array-back": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-usage": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "table-layout": "^0.4.2", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/command-line-usage/node_modules/array-back": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4" - } - }, - "glTF-Sample-Renderer/node_modules/common-sequence": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "glTF-Sample-Renderer/node_modules/config-master": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "walk-back": "^2.0.1" - } - }, - "glTF-Sample-Renderer/node_modules/config-master/node_modules/walk-back": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/dmd": { - "version": "6.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "common-sequence": "^2.0.2", - "file-set": "^4.0.2", - "handlebars": "^4.7.8", - "marked": "^4.3.0", - "object-get": "^2.1.1", - "reduce-flatten": "^3.0.1", - "reduce-unique": "^2.0.1", - "reduce-without": "^1.0.1", - "test-value": "^3.0.0", - "walk-back": "^5.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "glTF-Sample-Renderer/node_modules/file-set": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^5.0.0", - "glob": "^7.1.6" - }, - "engines": { - "node": ">=10" - } - }, - "glTF-Sample-Renderer/node_modules/file-set/node_modules/array-back": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "glTF-Sample-Renderer/node_modules/file-set/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "glTF-Sample-Renderer/node_modules/find-replace": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/find-replace/node_modules/array-back": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "glTF-Sample-Renderer/node_modules/fs-then-native": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/globals": { - "version": "15.9.0", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "glTF-Sample-Renderer/node_modules/handlebars": { - "version": "4.7.8", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "glTF-Sample-Renderer/node_modules/js2xmlparser": { - "version": "4.0.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "xmlcreate": "^2.0.4" - } - }, - "glTF-Sample-Renderer/node_modules/jsdoc": { - "version": "4.0.3", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^14.1.1", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^14.1.0", - "markdown-it-anchor": "^8.6.7", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/jsdoc-api": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "collect-all": "^1.0.4", - "file-set": "^4.0.2", - "fs-then-native": "^2.0.0", - "jsdoc": "^4.0.3", - "object-to-spawn-args": "^2.0.1", - "temp-path": "^1.0.0", - "walk-back": "^5.1.0" - }, - "engines": { - "node": ">=12.17" - } - }, - "glTF-Sample-Renderer/node_modules/jsdoc-parse": { - "version": "6.2.4", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^6.2.2", - "find-replace": "^5.0.1", - "lodash.omit": "^4.5.0", - "sort-array": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "glTF-Sample-Renderer/node_modules/jsdoc-parse/node_modules/find-replace": { - "version": "5.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@75lb/nature": "latest" - }, - "peerDependenciesMeta": { - "@75lb/nature": { - "optional": true - } - } - }, - "glTF-Sample-Renderer/node_modules/jsdoc-to-markdown": { - "version": "8.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^6.2.2", - "command-line-tool": "^0.8.0", - "config-master": "^3.1.0", - "dmd": "^6.2.3", - "jsdoc-api": "^8.1.1", - "jsdoc-parse": "^6.2.1", - "walk-back": "^5.1.0" - }, - "bin": { - "jsdoc2md": "bin/cli.js" - }, - "engines": { - "node": ">=12.17" - } - }, - "glTF-Sample-Renderer/node_modules/jsdoc/node_modules/escape-string-regexp": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "glTF-Sample-Renderer/node_modules/json-ptr": { - "version": "3.1.1", - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/klaw": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.9" - } - }, - "glTF-Sample-Renderer/node_modules/linkify-it": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/lodash.camelcase": { - "version": "4.3.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/lodash.omit": { - "version": "4.5.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/lodash.padend": { - "version": "4.6.1", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/markdown-it": { - "version": "14.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "glTF-Sample-Renderer/node_modules/markdown-it-anchor": { - "version": "8.6.7", - "dev": true, - "license": "Unlicense", - "peerDependencies": { - "@types/markdown-it": "*", - "markdown-it": "*" - } - }, - "glTF-Sample-Renderer/node_modules/marked": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "glTF-Sample-Renderer/node_modules/mdurl": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "glTF-Sample-Renderer/node_modules/mkdirp2": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/neo-async": { - "version": "2.6.2", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/object-get": { - "version": "2.1.1", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/object-to-spawn-args": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/punycode.js": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "glTF-Sample-Renderer/node_modules/reduce-flatten": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "glTF-Sample-Renderer/node_modules/reduce-unique": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "glTF-Sample-Renderer/node_modules/reduce-without": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "test-value": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/reduce-without/node_modules/array-back": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "glTF-Sample-Renderer/node_modules/reduce-without/node_modules/test-value": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^1.0.3", - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/requizzle": { - "version": "0.2.4", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.21" - } - }, - "glTF-Sample-Renderer/node_modules/sort-array": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^6.2.2", - "typical": "^7.1.1" - }, - "engines": { - "node": ">=12.17" - }, - "peerDependencies": { - "@75lb/nature": "^0.1.1" - }, - "peerDependenciesMeta": { - "@75lb/nature": { - "optional": true - } - } - }, - "glTF-Sample-Renderer/node_modules/sort-array/node_modules/typical": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.17" - } - }, - "glTF-Sample-Renderer/node_modules/stream-connect": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/stream-connect/node_modules/array-back": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "typical": "^2.6.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "glTF-Sample-Renderer/node_modules/stream-via": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/table-layout": { - "version": "0.4.5", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^2.0.0", - "deep-extend": "~0.6.0", - "lodash.padend": "^4.6.1", - "typical": "^2.6.1", - "wordwrapjs": "^3.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/table-layout/node_modules/array-back": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4" - } - }, - "glTF-Sample-Renderer/node_modules/temp-path": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/test-value": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^2.0.0", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/test-value/node_modules/array-back": { - "version": "2.0.0", - "dev": true, + "glTF-Sample-Renderer/node_modules/globals": { + "version": "15.9.0", "license": "MIT", - "dependencies": { - "typical": "^2.6.1" - }, "engines": { - "node": ">=4" - } - }, - "glTF-Sample-Renderer/node_modules/typical": { - "version": "2.6.1", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/uc.micro": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/uglify-js": { - "version": "3.19.3", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" + "node": ">=18" }, - "engines": { - "node": ">=0.8.0" - } - }, - "glTF-Sample-Renderer/node_modules/underscore": { - "version": "1.13.7", - "dev": true, - "license": "MIT" - }, - "glTF-Sample-Renderer/node_modules/walk-back": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.17" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "glTF-Sample-Renderer/node_modules/wordwrap": { - "version": "1.0.0", - "dev": true, + "glTF-Sample-Renderer/node_modules/json-ptr": { + "version": "3.1.1", "license": "MIT" }, - "glTF-Sample-Renderer/node_modules/wordwrapjs": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "reduce-flatten": "^1.0.1", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "glTF-Sample-Renderer/node_modules/wordwrapjs/node_modules/reduce-flatten": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "glTF-Sample-Renderer/node_modules/xmlcreate": { - "version": "2.0.4", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/@babel/helper-string-parser": { "version": "7.24.8", "license": "MIT", @@ -1126,14 +345,26 @@ "version": "1.5.0", "license": "MIT" }, - "node_modules/@khronosgroup/gltf-viewer": { - "resolved": "glTF-Sample-Renderer", - "link": true + "node_modules/@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } }, - "node_modules/@khronosgroup/khr-interactivity-authoring-engine": { + "node_modules/@khronosgroup/gltf-interactivity-sample-engine": { "resolved": "../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "link": true }, + "node_modules/@khronosgroup/gltf-viewer": { + "resolved": "glTF-Sample-Renderer", + "link": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -1567,6 +798,28 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, "node_modules/@types/minimatch": { "version": "5.1.2", "dev": true, @@ -1818,6 +1071,15 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/array-find-index": { "version": "1.0.2", "dev": true, @@ -1878,6 +1140,12 @@ "safe-buffer": "^5.1.1" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "node_modules/boxen": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", @@ -1950,6 +1218,26 @@ "node": ">= 0.8" } }, + "node_modules/cache-point": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.1.tgz", + "integrity": "sha512-itTIMLEKbh6Dw5DruXbxAgcyLnh/oPGVLBfTPqBOftASxHe8bAeXy7JkO4F0LvHqht7XqP5O/09h5UcHS2w0FA==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, "node_modules/call-bind": { "version": "1.0.7", "dev": true, @@ -1988,6 +1276,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -2168,6 +1468,44 @@ "dev": true, "license": "MIT" }, + "node_modules/command-line-args": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", + "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "find-replace": "^5.0.2", + "lodash.camelcase": "^4.3.0", + "typical": "^7.2.0" + }, + "engines": { + "node": ">=12.20" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/command-line-usage": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", + "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.0", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/commander": { "version": "2.20.3", "dev": true, @@ -2178,6 +1516,15 @@ "dev": true, "license": "MIT" }, + "node_modules/common-sequence": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-3.0.0.tgz", + "integrity": "sha512-g/CgSYk93y+a1IKm50tKl7kaT/OjjTYVQlEbUlt/49ZLV1mcKpUU7iyDiqTAeLdb4QDtQfq3ako8y8v//fzrWQ==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/commondir": { "version": "1.0.1", "dev": true, @@ -2315,6 +1662,24 @@ "dev": true, "license": "0BSD" }, + "node_modules/config-master": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", + "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", + "dev": true, + "dependencies": { + "walk-back": "^2.0.1" + } + }, + "node_modules/config-master/node_modules/walk-back": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", + "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -2354,6 +1719,15 @@ "version": "3.1.3", "license": "MIT" }, + "node_modules/current-module-paths": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.2.tgz", + "integrity": "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/date-fns": { "version": "2.30.0", "dev": true, @@ -2452,6 +1826,32 @@ "node": ">=8" } }, + "node_modules/dmd": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-7.1.1.tgz", + "integrity": "sha512-Ap2HP6iuOek7eShReDLr9jluNJm9RMZESlt29H/Xs1qrVMkcS9X6m5h1mBC56WMxNiSo0wvjGICmZlYUSFjwZQ==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "cache-point": "^3.0.0", + "common-sequence": "^3.0.0", + "file-set": "^5.2.2", + "handlebars": "^4.7.8", + "marked": "^4.3.0", + "walk-back": "^5.1.1" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, "node_modules/duplexify": { "version": "3.7.1", "dev": true, @@ -2848,12 +2248,33 @@ "node_modules/file-entry-cache": { "version": "8.0.0", "dev": true, - "license": "MIT", + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-set": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.3.0.tgz", + "integrity": "sha512-FKCxdjLX0J6zqTWdT0RXIxNF/n7MyXXnsSUp0syLEOCKdexvPZ02lNNv2a+gpK9E3hzUYF3+eFZe32ci7goNUg==", + "dev": true, "dependencies": { - "flat-cache": "^4.0.0" + "array-back": "^6.2.2", + "fast-glob": "^3.3.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/fill-range": { @@ -2867,6 +2288,23 @@ "node": ">=8" } }, + "node_modules/find-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", + "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, "node_modules/find-up": { "version": "5.0.0", "dev": true, @@ -3334,6 +2772,27 @@ "dev": true, "license": "ISC" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-flag": { "version": "4.0.0", "dev": true, @@ -3724,6 +3183,123 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", + "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc-api": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.5.tgz", + "integrity": "sha512-TQwh1jA8xtCkIbVwm/XA3vDRAa5JjydyKx1cC413Sh3WohDFxcMdwKSvn4LOsq2xWyAmOU/VnSChTQf6EF0R8g==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "cache-point": "^3.0.1", + "current-module-paths": "^1.1.2", + "file-set": "^5.3.0", + "jsdoc": "^4.0.4", + "object-to-spawn-args": "^2.0.1", + "walk-back": "^5.1.1" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/jsdoc-parse": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.5.tgz", + "integrity": "sha512-8JaSNjPLr2IuEY4Das1KM6Z4oLHZYUnjRrr27hKSa78Cj0i5Lur3DzNnCkz+DfrKBDoljGMoWOiBVQbtUZJBPw==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "find-replace": "^5.0.1", + "sort-array": "^5.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdoc-to-markdown": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-9.1.3.tgz", + "integrity": "sha512-i9wi+6WHX0WKziv0ar88T8h7OmxA0LWdQaV23nY6uQyKvdUPzVt0o6YAaOceFuKRF5Rvlju5w/KnZBfdpDAlnw==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "command-line-args": "^6.0.1", + "command-line-usage": "^7.0.3", + "config-master": "^3.1.0", + "dmd": "^7.1.1", + "jsdoc-api": "^9.3.5", + "jsdoc-parse": "^6.2.5", + "walk-back": "^5.1.1" + }, + "bin": { + "jsdoc2md": "bin/cli.js" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "dev": true, @@ -3755,6 +3331,15 @@ "json-buffer": "3.0.1" } }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -3767,6 +3352,15 @@ "node": ">= 0.8.0" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "dev": true, @@ -3786,6 +3380,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, @@ -3819,6 +3419,51 @@ "wrappy": "1" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3901,6 +3546,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.30.1", "dev": true, @@ -3949,6 +3606,12 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "node_modules/nodemon": { "version": "3.1.7", "dev": true, @@ -4042,6 +3705,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-to-spawn-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", + "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/on-headers": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", @@ -4398,6 +4070,15 @@ "dev": true, "license": "MIT" }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.13.0", "dev": true, @@ -4538,6 +4219,15 @@ "dev": true, "license": "MIT" }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/resolve": { "version": "1.22.8", "dev": true, @@ -5077,6 +4767,27 @@ "node": ">=8" } }, + "node_modules/sort-array": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-5.1.1.tgz", + "integrity": "sha512-EltS7AIsNlAFIM9cayrgKrM6XP94ATWwXP4LCL4IQbvbYhELSt2hZTrixg+AaQwnWFs/JGJgqU3rxMcNNWxGAA==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "^0.1.1" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, "node_modules/source-map": { "version": "0.6.1", "dev": true, @@ -5304,6 +5015,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" + }, + "engines": { + "node": ">=12.17" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -5391,16 +5115,50 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "dev": true, - "license": "MIT" - }, + "node_modules/typedarray": { + "version": "0.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/typical": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "dev": true, "license": "MIT" }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -5500,6 +5258,15 @@ } } }, + "node_modules/walk-back": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz", + "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/whatwg-encoding": { "version": "2.0.0", "dev": true, @@ -5548,6 +5315,21 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wordwrapjs": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", + "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "dev": true, @@ -5640,6 +5422,12 @@ "dev": true, "license": "ISC" }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, "node_modules/xtend": { "version": "4.0.2", "dev": true, @@ -5853,581 +5641,57 @@ "@jridgewell/sourcemap-codec": { "version": "1.5.0" }, + "@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "@khronosgroup/gltf-interactivity-sample-engine": { + "version": "file:../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "requires": { + "@types/node": "^24.1.0", + "gl-matrix": "^3.4.3", + "typescript": "^5.8.3" + } + }, "@khronosgroup/gltf-viewer": { "version": "file:glTF-Sample-Renderer", "requires": { - "@khronosgroup/khr-interactivity-authoring-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", + "@khronosgroup/gltf-interactivity-sample-engine": "file:../../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", "@playwright/test": "^1.56.0", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-wasm": "^6.2.2", - "@types/node": "^24.7.2", - "concurrently": "^8.2.2", - "eslint": "^9.5.0", - "eslint-config-prettier": "^10.1.8", - "fast-png": "^6.2.0", - "gl-matrix": "^3.2.1", - "globals": "^15.5.0", - "jpeg-js": "^0.4.3", - "jsdoc-to-markdown": "^8.0.1", - "json-ptr": "^3.1.0", - "prettier": "3.6.2", - "rollup": "^4.23.0", - "rollup-plugin-copy": "^3.5.0", - "rollup-plugin-glslify": "^1.3.1", - "rollup-plugin-license": "^3.5.2", - "serve": "^14.2.5" - }, - "dependencies": { - "@jsdoc/salty": { - "version": "0.2.8", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "@types/linkify-it": { - "version": "5.0.0", - "dev": true - }, - "@types/markdown-it": { - "version": "14.1.2", - "dev": true, - "requires": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" - } - }, - "@types/mdurl": { - "version": "2.0.0", - "dev": true - }, - "ansi-escape-sequences": { - "version": "4.1.0", - "dev": true, - "requires": { - "array-back": "^3.0.1" - }, - "dependencies": { - "array-back": { - "version": "3.1.0", - "dev": true - } - } - }, - "array-back": { - "version": "6.2.2", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "dev": true - }, - "cache-point": { - "version": "2.0.0", - "dev": true, - "requires": { - "array-back": "^4.0.1", - "fs-then-native": "^2.0.0", - "mkdirp2": "^1.0.4" - }, - "dependencies": { - "array-back": { - "version": "4.0.2", - "dev": true - } - } - }, - "catharsis": { - "version": "0.9.0", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "collect-all": { - "version": "1.0.4", - "dev": true, - "requires": { - "stream-connect": "^1.0.2", - "stream-via": "^1.0.4" - } - }, - "command-line-args": { - "version": "5.2.1", - "dev": true, - "requires": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "dependencies": { - "array-back": { - "version": "3.1.0", - "dev": true - }, - "typical": { - "version": "4.0.0", - "dev": true - } - } - }, - "command-line-tool": { - "version": "0.8.0", - "dev": true, - "requires": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "command-line-args": "^5.0.0", - "command-line-usage": "^4.1.0", - "typical": "^2.6.1" - }, - "dependencies": { - "array-back": { - "version": "2.0.0", - "dev": true, - "requires": { - "typical": "^2.6.1" - } - } - } - }, - "command-line-usage": { - "version": "4.1.0", - "dev": true, - "requires": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "table-layout": "^0.4.2", - "typical": "^2.6.1" - }, - "dependencies": { - "array-back": { - "version": "2.0.0", - "dev": true, - "requires": { - "typical": "^2.6.1" - } - } - } - }, - "common-sequence": { - "version": "2.0.2", - "dev": true - }, - "config-master": { - "version": "3.1.0", - "dev": true, - "requires": { - "walk-back": "^2.0.1" - }, - "dependencies": { - "walk-back": { - "version": "2.0.1", - "dev": true - } - } - }, - "dmd": { - "version": "6.2.3", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "common-sequence": "^2.0.2", - "file-set": "^4.0.2", - "handlebars": "^4.7.8", - "marked": "^4.3.0", - "object-get": "^2.1.1", - "reduce-flatten": "^3.0.1", - "reduce-unique": "^2.0.1", - "reduce-without": "^1.0.1", - "test-value": "^3.0.0", - "walk-back": "^5.1.0" - } - }, - "file-set": { - "version": "4.0.2", - "dev": true, - "requires": { - "array-back": "^5.0.0", - "glob": "^7.1.6" - }, - "dependencies": { - "array-back": { - "version": "5.0.0", - "dev": true - }, - "glob": { - "version": "7.2.3", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "find-replace": { - "version": "3.0.0", - "dev": true, - "requires": { - "array-back": "^3.0.1" - }, - "dependencies": { - "array-back": { - "version": "3.1.0", - "dev": true - } - } - }, - "fs-then-native": { - "version": "2.0.0", - "dev": true - }, - "globals": { - "version": "15.9.0" - }, - "handlebars": { - "version": "4.7.8", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, - "js2xmlparser": { - "version": "4.0.2", - "dev": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, - "jsdoc": { - "version": "4.0.3", - "dev": true, - "requires": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^14.1.1", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^14.1.0", - "markdown-it-anchor": "^8.6.7", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "dev": true - } - } - }, - "jsdoc-api": { - "version": "8.1.1", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "collect-all": "^1.0.4", - "file-set": "^4.0.2", - "fs-then-native": "^2.0.0", - "jsdoc": "^4.0.3", - "object-to-spawn-args": "^2.0.1", - "temp-path": "^1.0.0", - "walk-back": "^5.1.0" - } - }, - "jsdoc-parse": { - "version": "6.2.4", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "find-replace": "^5.0.1", - "lodash.omit": "^4.5.0", - "sort-array": "^5.0.0" - }, - "dependencies": { - "find-replace": { - "version": "5.0.2", - "dev": true, - "requires": {} - } - } - }, - "jsdoc-to-markdown": { - "version": "8.0.3", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "command-line-tool": "^0.8.0", - "config-master": "^3.1.0", - "dmd": "^6.2.3", - "jsdoc-api": "^8.1.1", - "jsdoc-parse": "^6.2.1", - "walk-back": "^5.1.0" - } - }, - "json-ptr": { - "version": "3.1.1" - }, - "klaw": { - "version": "3.0.0", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "linkify-it": { - "version": "5.0.0", - "dev": true, - "requires": { - "uc.micro": "^2.0.0" - } - }, - "lodash.camelcase": { - "version": "4.3.0", - "dev": true - }, - "lodash.omit": { - "version": "4.5.0", - "dev": true - }, - "lodash.padend": { - "version": "4.6.1", - "dev": true - }, - "markdown-it": { - "version": "14.1.0", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - } - }, - "markdown-it-anchor": { - "version": "8.6.7", - "dev": true, - "requires": {} - }, - "marked": { - "version": "4.3.0", - "dev": true - }, - "mdurl": { - "version": "2.0.0", - "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "dev": true - }, - "mkdirp2": { - "version": "1.0.5", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "dev": true - }, - "object-get": { - "version": "2.1.1", - "dev": true - }, - "object-to-spawn-args": { - "version": "2.0.1", - "dev": true - }, - "punycode.js": { - "version": "2.3.1", - "dev": true - }, - "reduce-flatten": { - "version": "3.0.1", - "dev": true - }, - "reduce-unique": { - "version": "2.0.1", - "dev": true - }, - "reduce-without": { - "version": "1.0.1", - "dev": true, - "requires": { - "test-value": "^2.0.0" - }, - "dependencies": { - "array-back": { - "version": "1.0.4", - "dev": true, - "requires": { - "typical": "^2.6.0" - } - }, - "test-value": { - "version": "2.1.0", - "dev": true, - "requires": { - "array-back": "^1.0.3", - "typical": "^2.6.0" - } - } - } - }, - "requizzle": { - "version": "0.2.4", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "sort-array": { - "version": "5.0.0", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "typical": "^7.1.1" - }, - "dependencies": { - "typical": { - "version": "7.2.0", - "dev": true - } - } - }, - "stream-connect": { - "version": "1.0.2", - "dev": true, - "requires": { - "array-back": "^1.0.2" - }, - "dependencies": { - "array-back": { - "version": "1.0.4", - "dev": true, - "requires": { - "typical": "^2.6.0" - } - } - } - }, - "stream-via": { - "version": "1.0.4", - "dev": true - }, - "table-layout": { - "version": "0.4.5", - "dev": true, - "requires": { - "array-back": "^2.0.0", - "deep-extend": "~0.6.0", - "lodash.padend": "^4.6.1", - "typical": "^2.6.1", - "wordwrapjs": "^3.0.0" - }, - "dependencies": { - "array-back": { - "version": "2.0.0", - "dev": true, - "requires": { - "typical": "^2.6.1" - } - } - } - }, - "temp-path": { - "version": "1.0.0", - "dev": true - }, - "test-value": { - "version": "3.0.0", - "dev": true, - "requires": { - "array-back": "^2.0.0", - "typical": "^2.6.1" - }, - "dependencies": { - "array-back": { - "version": "2.0.0", - "dev": true, - "requires": { - "typical": "^2.6.1" - } - } - } - }, - "typical": { - "version": "2.6.1", - "dev": true - }, - "uc.micro": { - "version": "2.1.0", - "dev": true - }, - "uglify-js": { - "version": "3.19.3", - "dev": true, - "optional": true - }, - "underscore": { - "version": "1.13.7", - "dev": true - }, - "walk-back": { - "version": "5.1.1", - "dev": true - }, - "wordwrap": { - "version": "1.0.0", - "dev": true - }, - "wordwrapjs": { - "version": "3.0.0", - "dev": true, - "requires": { - "reduce-flatten": "^1.0.1", - "typical": "^2.6.1" - }, - "dependencies": { - "reduce-flatten": { - "version": "1.0.1", - "dev": true - } - } + "@types/node": "^24.7.2", + "concurrently": "^8.2.2", + "eslint": "^9.5.0", + "eslint-config-prettier": "^10.1.8", + "fast-png": "^6.2.0", + "gl-matrix": "^3.2.1", + "globals": "^15.5.0", + "jpeg-js": "^0.4.3", + "jsdoc-to-markdown": "^9.1.3", + "json-ptr": "^3.1.0", + "prettier": "3.6.2", + "rollup": "^4.23.0", + "rollup-plugin-copy": "^3.5.0", + "rollup-plugin-glslify": "^1.3.1", + "rollup-plugin-license": "^3.5.2", + "serve": "^14.2.5" + }, + "dependencies": { + "globals": { + "version": "15.9.0" }, - "xmlcreate": { - "version": "2.0.4", - "dev": true + "json-ptr": { + "version": "3.1.1" } } }, - "@khronosgroup/khr-interactivity-authoring-engine": { - "version": "file:../glTF-InteractivityGraph-AuthoringTool/src/BasicBehaveEngine", - "requires": { - "@types/node": "^24.1.0", - "gl-matrix": "^3.4.3", - "typescript": "^5.8.3" - } - }, "@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -6655,6 +5919,28 @@ "version": "7.0.15", "dev": true }, + "@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "requires": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, "@types/minimatch": { "version": "5.1.2", "dev": true @@ -6841,6 +6127,12 @@ "version": "2.0.1", "dev": true }, + "array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true + }, "array-find-index": { "version": "1.0.2", "dev": true @@ -6879,6 +6171,12 @@ "safe-buffer": "^5.1.1" } }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "boxen": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", @@ -6931,6 +6229,15 @@ "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true }, + "cache-point": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.1.tgz", + "integrity": "sha512-itTIMLEKbh6Dw5DruXbxAgcyLnh/oPGVLBfTPqBOftASxHe8bAeXy7JkO4F0LvHqht7XqP5O/09h5UcHS2w0FA==", + "dev": true, + "requires": { + "array-back": "^6.2.2" + } + }, "call-bind": { "version": "1.0.7", "dev": true, @@ -6952,6 +6259,15 @@ "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true }, + "catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, "chalk": { "version": "4.1.2", "dev": true, @@ -7070,6 +6386,30 @@ "version": "1.4.0", "dev": true }, + "command-line-args": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", + "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "find-replace": "^5.0.2", + "lodash.camelcase": "^4.3.0", + "typical": "^7.2.0" + } + }, + "command-line-usage": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", + "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.0", + "typical": "^7.1.1" + } + }, "commander": { "version": "2.20.3", "dev": true @@ -7078,6 +6418,12 @@ "version": "1.1.0", "dev": true }, + "common-sequence": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-3.0.0.tgz", + "integrity": "sha512-g/CgSYk93y+a1IKm50tKl7kaT/OjjTYVQlEbUlt/49ZLV1mcKpUU7iyDiqTAeLdb4QDtQfq3ako8y8v//fzrWQ==", + "dev": true + }, "commondir": { "version": "1.0.1", "dev": true @@ -7177,6 +6523,23 @@ } } }, + "config-master": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", + "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", + "dev": true, + "requires": { + "walk-back": "^2.0.1" + }, + "dependencies": { + "walk-back": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", + "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", + "dev": true + } + } + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -7203,6 +6566,12 @@ "csstype": { "version": "3.1.3" }, + "current-module-paths": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.2.tgz", + "integrity": "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ==", + "dev": true + }, "date-fns": { "version": "2.30.0", "dev": true, @@ -7261,6 +6630,21 @@ "path-type": "^4.0.0" } }, + "dmd": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-7.1.1.tgz", + "integrity": "sha512-Ap2HP6iuOek7eShReDLr9jluNJm9RMZESlt29H/Xs1qrVMkcS9X6m5h1mBC56WMxNiSo0wvjGICmZlYUSFjwZQ==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "cache-point": "^3.0.0", + "common-sequence": "^3.0.0", + "file-set": "^5.2.2", + "handlebars": "^4.7.8", + "marked": "^4.3.0", + "walk-back": "^5.1.1" + } + }, "duplexify": { "version": "3.7.1", "dev": true, @@ -7519,6 +6903,16 @@ "flat-cache": "^4.0.0" } }, + "file-set": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.3.0.tgz", + "integrity": "sha512-FKCxdjLX0J6zqTWdT0RXIxNF/n7MyXXnsSUp0syLEOCKdexvPZ02lNNv2a+gpK9E3hzUYF3+eFZe32ci7goNUg==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "fast-glob": "^3.3.2" + } + }, "fill-range": { "version": "7.1.1", "dev": true, @@ -7526,6 +6920,13 @@ "to-regex-range": "^5.0.1" } }, + "find-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", + "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", + "dev": true, + "requires": {} + }, "find-up": { "version": "5.0.0", "dev": true, @@ -7863,6 +7264,19 @@ "version": "4.2.11", "dev": true }, + "handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, "has-flag": { "version": "4.0.0", "dev": true @@ -8099,6 +7513,88 @@ "argparse": "^2.0.1" } }, + "js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "requires": { + "xmlcreate": "^2.0.4" + } + }, + "jsdoc": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", + "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "jsdoc-api": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.5.tgz", + "integrity": "sha512-TQwh1jA8xtCkIbVwm/XA3vDRAa5JjydyKx1cC413Sh3WohDFxcMdwKSvn4LOsq2xWyAmOU/VnSChTQf6EF0R8g==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "cache-point": "^3.0.1", + "current-module-paths": "^1.1.2", + "file-set": "^5.3.0", + "jsdoc": "^4.0.4", + "object-to-spawn-args": "^2.0.1", + "walk-back": "^5.1.1" + } + }, + "jsdoc-parse": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.5.tgz", + "integrity": "sha512-8JaSNjPLr2IuEY4Das1KM6Z4oLHZYUnjRrr27hKSa78Cj0i5Lur3DzNnCkz+DfrKBDoljGMoWOiBVQbtUZJBPw==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "find-replace": "^5.0.1", + "sort-array": "^5.0.0" + } + }, + "jsdoc-to-markdown": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-9.1.3.tgz", + "integrity": "sha512-i9wi+6WHX0WKziv0ar88T8h7OmxA0LWdQaV23nY6uQyKvdUPzVt0o6YAaOceFuKRF5Rvlju5w/KnZBfdpDAlnw==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "command-line-args": "^6.0.1", + "command-line-usage": "^7.0.3", + "config-master": "^3.1.0", + "dmd": "^7.1.1", + "jsdoc-api": "^9.3.5", + "jsdoc-parse": "^6.2.5", + "walk-back": "^5.1.1" + } + }, "json-buffer": { "version": "3.0.1", "dev": true @@ -8125,6 +7621,15 @@ "json-buffer": "3.0.1" } }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, "levn": { "version": "0.4.1", "dev": true, @@ -8133,6 +7638,15 @@ "type-check": "~0.4.0" } }, + "linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "requires": { + "uc.micro": "^2.0.0" + } + }, "locate-path": { "version": "6.0.0", "dev": true, @@ -8144,6 +7658,12 @@ "version": "4.17.21", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "dev": true @@ -8174,6 +7694,39 @@ } } }, + "markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + } + }, + "markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "requires": {} + }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true + }, + "mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -8223,6 +7776,12 @@ "version": "7.1.2", "dev": true }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, "moment": { "version": "2.30.1", "dev": true @@ -8248,6 +7807,12 @@ "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "nodemon": { "version": "3.1.7", "dev": true, @@ -8305,6 +7870,12 @@ "version": "1.13.2", "dev": true }, + "object-to-spawn-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", + "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", + "dev": true + }, "on-headers": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", @@ -8515,6 +8086,12 @@ "version": "1.1.8", "dev": true }, + "punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true + }, "qs": { "version": "6.13.0", "dev": true, @@ -8611,6 +8188,15 @@ "version": "1.0.0", "dev": true }, + "requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, "resolve": { "version": "1.22.8", "dev": true, @@ -8954,6 +8540,16 @@ "version": "3.0.0", "dev": true }, + "sort-array": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-5.1.1.tgz", + "integrity": "sha512-EltS7AIsNlAFIM9cayrgKrM6XP94ATWwXP4LCL4IQbvbYhELSt2hZTrixg+AaQwnWFs/JGJgqU3rxMcNNWxGAA==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "typical": "^7.1.1" + } + }, "source-map": { "version": "0.6.1", "dev": true @@ -9104,6 +8700,16 @@ "version": "1.0.0", "dev": true }, + "table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" + } + }, "text-table": { "version": "0.2.0", "dev": true @@ -9164,10 +8770,35 @@ "version": "0.0.6", "dev": true }, + "typical": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "dev": true + }, + "uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, + "uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true + }, "undefsafe": { "version": "2.0.5", "dev": true }, + "underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true + }, "undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -9243,6 +8874,12 @@ "@vue/shared": "3.5.10" } }, + "walk-back": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz", + "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==", + "dev": true + }, "whatwg-encoding": { "version": "2.0.0", "dev": true, @@ -9270,6 +8907,18 @@ "version": "1.2.5", "dev": true }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "wordwrapjs": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", + "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", + "dev": true + }, "wrap-ansi": { "version": "8.1.0", "dev": true, @@ -9324,6 +8973,12 @@ "version": "1.0.2", "dev": true }, + "xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, "xtend": { "version": "4.0.2", "dev": true diff --git a/src/main.js b/src/main.js index 28521ce5..32a81c29 100644 --- a/src/main.js +++ b/src/main.js @@ -323,8 +323,20 @@ export default async () => { state.graphController.initializeGraphs(state); const graphIndex = state.gltf.extensions.KHR_interactivity.graph ?? 0; state.graphController.loadGraph(graphIndex); + if (app.graphState) { + state.graphController.resumeGraph(); + state.animationTimer.unpause(); + } else { + state.graphController.pauseGraph(); + state.animationTimer.pause(); + } } else { state.graphController.stopGraphEngine(); + if (app.animationState) { + state.animationTimer.unpause(); + } else { + state.animationTimer.pause(); + } } }); listenForRedraw(uiModel.interactivityEnabled);