@3driseai/3drise-viewer 0.1.32 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
  2. package/dist/animationsV2/ClipsRuntime.js +11 -1
  3. package/dist/animationsV2/animationLive.d.ts +7 -0
  4. package/dist/animationsV2/animationLive.d.ts.map +1 -0
  5. package/dist/animationsV2/animationLive.js +26 -0
  6. package/dist/animationsV2/appliers.d.ts +8 -0
  7. package/dist/animationsV2/appliers.d.ts.map +1 -1
  8. package/dist/animationsV2/appliers.js +61 -0
  9. package/dist/animationsV2/index.d.ts +1 -0
  10. package/dist/animationsV2/index.d.ts.map +1 -1
  11. package/dist/animationsV2/index.js +1 -0
  12. package/dist/components/AnimatedObject.d.ts.map +1 -1
  13. package/dist/components/AnimatedObject.js +2 -0
  14. package/dist/components/CameraController.d.ts.map +1 -1
  15. package/dist/components/CameraController.js +9 -0
  16. package/dist/components/CreatedObject.d.ts.map +1 -1
  17. package/dist/components/CreatedObject.js +4 -1
  18. package/dist/components/GroupMaterialContext.d.ts +25 -0
  19. package/dist/components/GroupMaterialContext.d.ts.map +1 -0
  20. package/dist/components/GroupMaterialContext.js +21 -0
  21. package/dist/components/ObjectNode.d.ts.map +1 -1
  22. package/dist/components/ObjectNode.js +13 -2
  23. package/dist/components/ObjectsRenderer.d.ts.map +1 -1
  24. package/dist/components/ObjectsRenderer.js +26 -19
  25. package/dist/components/SceneBuilder.d.ts.map +1 -1
  26. package/dist/components/SceneBuilder.js +7 -4
  27. package/dist/components/land/LandPatch.d.ts.map +1 -1
  28. package/dist/components/land/LandPatch.js +15 -1
  29. package/dist/hooks/useContinuousEffects.d.ts.map +1 -1
  30. package/dist/hooks/useContinuousEffects.js +24 -3
  31. package/dist/hooks/useMaterialApplication.d.ts.map +1 -1
  32. package/dist/hooks/useMaterialApplication.js +2 -1
  33. package/dist/hooks/useMaterialUniforms.d.ts +2 -8
  34. package/dist/hooks/useMaterialUniforms.d.ts.map +1 -1
  35. package/dist/hooks/useMaterialUniforms.js +18 -6
  36. package/dist/hooks/useOrbitTargetFollow.d.ts.map +1 -1
  37. package/dist/hooks/useOrbitTargetFollow.js +6 -4
  38. package/dist/operations/bake.d.ts +36 -0
  39. package/dist/operations/bake.d.ts.map +1 -0
  40. package/dist/operations/bake.js +113 -0
  41. package/dist/operations/catalogue/physicalHeld.d.ts.map +1 -1
  42. package/dist/operations/catalogue/physicalHeld.js +6 -0
  43. package/dist/operations/catalogue/shaderLayers.js +2 -2
  44. package/dist/operations/catalogue/warmup.d.ts +23 -1
  45. package/dist/operations/catalogue/warmup.d.ts.map +1 -1
  46. package/dist/operations/catalogue/warmup.js +200 -12
  47. package/dist/operations/index.d.ts +3 -1
  48. package/dist/operations/index.d.ts.map +1 -1
  49. package/dist/operations/index.js +3 -1
  50. package/dist/operations/objectEffects.d.ts +15 -1
  51. package/dist/operations/objectEffects.d.ts.map +1 -1
  52. package/dist/operations/objectEffects.js +49 -1
  53. package/dist/operations/runtime.d.ts +17 -9
  54. package/dist/operations/runtime.d.ts.map +1 -1
  55. package/dist/operations/runtime.js +71 -18
  56. package/dist/operations/types.d.ts +5 -0
  57. package/dist/operations/types.d.ts.map +1 -1
  58. package/dist/triggers/readiness.d.ts +2 -0
  59. package/dist/triggers/readiness.d.ts.map +1 -1
  60. package/dist/triggers/readiness.js +28 -3
  61. package/dist/utils/stallLog.d.ts +4 -0
  62. package/dist/utils/stallLog.d.ts.map +1 -0
  63. package/dist/utils/stallLog.js +88 -0
  64. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  import { useRef, useEffect } from "react";
2
+ import { animationLiveReader } from "../animationsV2/animationLive.js";
2
3
  import { useFrame } from "@react-three/fiber";
3
- import { animateUniforms, cacheChildrenWithMaterials, handleEdgesAnimations, handleMaterialAnimations, handleMaterialEffects, handleTransformAnimations } from "@3driseai/3drise-core";
4
+ import { AnimationTargetState, animateUniforms, cacheChildrenWithMaterials, handleEdgesAnimations, handleMaterialAnimations, handleMaterialEffects, handleTransformAnimations, targetRootKind } from "@3driseai/3drise-core";
4
5
  import usePathAnimation from "./usePathAnimation.js";
5
6
  import { resolveObject3D } from "../utils/resolveObject3D.js";
6
7
  export const useContinuousEffects = (
@@ -19,6 +20,9 @@ objectSettings, options = {}, objectSource) => {
19
20
  const startValuesRef = useRef({});
20
21
  // Cache start values for edges animations
21
22
  const edgesStartValuesRef = useRef({});
23
+ // Groups / models: rows scoped each / targets (core animationTargets.ts) — one state per object.
24
+ const targetsRef = useRef(null);
25
+ useEffect(() => () => { targetsRef.current?.dispose(); targetsRef.current = null; }, []);
22
26
  // Transform keyframes. Effects that move the object (float, sway, spin…) are object
23
27
  // effects now (CreatedObject.effects, the operations catalogue) and ride on top of these.
24
28
  const transformAnimations = objectSettings?.animations?.transform?.animations || [];
@@ -74,8 +78,15 @@ objectSettings, options = {}, objectSource) => {
74
78
  }, [enabled, objectSettings?.animations?.transform?.animations, objectSource, startPathAnimation, stopPathAnimation]);
75
79
  useFrame((state, delta) => {
76
80
  const object = resolveObject3D(objectSource);
77
- if (!enabled || !object || !objectSettings)
81
+ if (!enabled || !object || !objectSettings) {
82
+ // Off: the parts the rows moved go back to their rest.
83
+ if (targetsRef.current) {
84
+ targetsRef.current.dispose();
85
+ targetsRef.current = null;
86
+ lastObjectRef.current = null;
87
+ }
78
88
  return;
89
+ }
79
90
  // Cache the object's materials the first frame we actually see it, and
80
91
  // again if the caller swaps the object underneath us.
81
92
  if (object !== lastObjectRef.current) {
@@ -83,7 +94,11 @@ objectSettings, options = {}, objectSource) => {
83
94
  childrenWithMaterialsRef.current = cacheChildrenWithMaterials(object);
84
95
  startValuesRef.current = {};
85
96
  edgesStartValuesRef.current = {};
97
+ targetsRef.current?.dispose();
98
+ targetsRef.current = targetRootKind(object) ? new AnimationTargetState(object) : null;
86
99
  }
100
+ const targets = targetsRef.current;
101
+ targets?.beginFrame();
87
102
  const time = state.clock.getElapsedTime();
88
103
  const mouse = state.pointer;
89
104
  const currentTime = Date.now();
@@ -97,7 +112,10 @@ objectSettings, options = {}, objectSource) => {
97
112
  object,
98
113
  meshSettings: objectSettings.meshSettings || {},
99
114
  pathIsActive,
100
- }, activeTransformAnimations, currentTime, hovered);
115
+ targets: targets ?? undefined,
116
+ // a timeline clip driving a row's value (live, while it runs)
117
+ liveTo: animationLiveReader(objectSettings.id),
118
+ }, activeTransformAnimations, currentTime, hovered, delta);
101
119
  }
102
120
  if (hasEdgesAnimations) {
103
121
  handleEdgesAnimations({ object, startValuesCache: edgesStartValuesRef.current }, edgesAnimations, currentTime, hovered);
@@ -109,6 +127,7 @@ objectSettings, options = {}, objectSource) => {
109
127
  object,
110
128
  materialSettings: objectSettings.materialSettings || {},
111
129
  startValuesCache: startValuesRef.current,
130
+ targets: targets ?? undefined,
112
131
  }, activeMaterialAnimations, currentTime, hovered);
113
132
  }
114
133
  // Handle material effects (color effects)
@@ -116,6 +135,8 @@ objectSettings, options = {}, objectSource) => {
116
135
  handleMaterialEffects(object, enabledMaterialEffects, time, delta, effectStateRef, applyToChildren);
117
136
  }
118
137
  }
138
+ // Targets the rows stopped driving go back to their rest.
139
+ targets?.endFrame();
119
140
  animateUniforms(childrenWithMaterialsRef.current, time * speed, mouse, state.camera.position);
120
141
  });
121
142
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"useMaterialApplication.d.ts","sourceRoot":"","sources":["../../src/hooks/useMaterialApplication.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,eAAO,MAAM,sBAAsB,GAAI,QAAQ,cAAc,EAAE,kBAAkB,gBAAgB,EAAE,4BAA4B,OAAO,EAAE,YAAY,MAAM,IAAI,KAAG,IAwIhK,CAAC"}
1
+ {"version":3,"file":"useMaterialApplication.d.ts","sourceRoot":"","sources":["../../src/hooks/useMaterialApplication.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,eAAO,MAAM,sBAAsB,GAAI,QAAQ,cAAc,EAAE,kBAAkB,gBAAgB,EAAE,4BAA4B,OAAO,EAAE,YAAY,MAAM,IAAI,KAAG,IAyIhK,CAAC"}
@@ -96,11 +96,12 @@ export const useMaterialApplication = (source, materialSettings, shouldApply3dri
96
96
  onApplied?.();
97
97
  return;
98
98
  }
99
+ // Stops at child scene objects: they apply their own material.
99
100
  traverseSkippingEdgesAndEffects(obj, true, (child) => {
100
101
  if (child && child.material) {
101
102
  applyMaterialToChild(child, variant, resolvedSettings);
102
103
  }
103
- });
104
+ }, true);
104
105
  }
105
106
  // traverseSkippingEdges(originObject!, true, (child: any) => {
106
107
  // if (child && child.material) {
@@ -1,14 +1,8 @@
1
1
  import type { Material, Object3D } from "three";
2
2
  /**
3
- * Hook for direct material manipulation on a scene object ref.
4
- *
5
- * Usage pattern (like SkyControllerUi):
6
- * - On slider drag → updateProperty(key, value) — instant visual feedback, no Redux
7
- * - On slider end → updateProperty(key, value) + dispatch to Redux
8
- * - On color change → updateColor(key, hex) + dispatch to Redux
9
- * - On variant change → changeMaterial(variant, settings) + dispatch to Redux
3
+ * `object` may be several objects (a group's Material tab edits the children it applies to).
10
4
  */
11
- export declare function useMaterialUniforms(object: Object3D | null | undefined): {
5
+ export declare function useMaterialUniforms(object: Object3D | Object3D[] | null | undefined): {
12
6
  getMaterial: () => Material | null;
13
7
  updateProperty: (key: string, value: any) => void;
14
8
  updateColor: (key: string, hexValue: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useMaterialUniforms.d.ts","sourceRoot":"","sources":["../../src/hooks/useMaterialUniforms.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG;IAClE,WAAW,EAAE,MAAM,QAAQ,GAAG,IAAI,CAAC;IACnC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC1D,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CAC5E,CAoFJ"}
1
+ {"version":3,"file":"useMaterialUniforms.d.ts","sourceRoot":"","sources":["../../src/hooks/useMaterialUniforms.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAmBhD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG;IAC/E,WAAW,EAAE,MAAM,QAAQ,GAAG,IAAI,CAAC;IACnC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC1D,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CAC5E,CAoFJ"}
@@ -9,6 +9,18 @@ import { applySingleProperty, applyColorProperty, createAndApplyMaterial, MATERI
9
9
  * - On color change → updateColor(key, hex) + dispatch to Redux
10
10
  * - On variant change → changeMaterial(variant, settings) + dispatch to Redux
11
11
  */
12
+ /** Every material-bearing node of the object(s) — never inside child scene objects (they have their own material). */
13
+ function eachNode(object, cb) {
14
+ if (!object)
15
+ return;
16
+ for (const root of Array.isArray(object) ? object : [object]) {
17
+ if (root)
18
+ traverseSkippingEdgesAndEffects(root, true, cb, true);
19
+ }
20
+ }
21
+ /**
22
+ * `object` may be several objects (a group's Material tab edits the children it applies to).
23
+ */
12
24
  export function useMaterialUniforms(object) {
13
25
  /**
14
26
  * Get the material from the first non-edges child mesh that has one.
@@ -16,10 +28,10 @@ export function useMaterialUniforms(object) {
16
28
  const getMaterial = useCallback(() => {
17
29
  if (!object)
18
30
  return null;
19
- if (object.material)
31
+ if (!Array.isArray(object) && object.material)
20
32
  return object.material;
21
33
  let found = null;
22
- traverseSkippingEdgesAndEffects(object, true, (child) => {
34
+ eachNode(object, (child) => {
23
35
  if (!found && child.material) {
24
36
  found = child.material;
25
37
  }
@@ -33,7 +45,7 @@ export function useMaterialUniforms(object) {
33
45
  const updateProperty = useCallback((key, value) => {
34
46
  if (!object)
35
47
  return;
36
- traverseSkippingEdgesAndEffects(object, true, (child) => {
48
+ eachNode(object, (child) => {
37
49
  if (child.material) {
38
50
  applySingleProperty(child.material, key, value);
39
51
  }
@@ -45,7 +57,7 @@ export function useMaterialUniforms(object) {
45
57
  const updateColor = useCallback((key, hexValue) => {
46
58
  if (!object)
47
59
  return;
48
- traverseSkippingEdgesAndEffects(object, true, (child) => {
60
+ eachNode(object, (child) => {
49
61
  if (child.material) {
50
62
  applyColorProperty(child.material, key, hexValue);
51
63
  }
@@ -58,7 +70,7 @@ export function useMaterialUniforms(object) {
58
70
  const applyAllSettings = useCallback((settings) => {
59
71
  if (!object)
60
72
  return;
61
- traverseSkippingEdgesAndEffects(object, true, (child) => {
73
+ eachNode(object, (child) => {
62
74
  if (child.material) {
63
75
  MaterialRegistryAPI.applySettings(child.material, settings);
64
76
  }
@@ -71,7 +83,7 @@ export function useMaterialUniforms(object) {
71
83
  const changeMaterial = useCallback((variant, settings) => {
72
84
  if (!object)
73
85
  return;
74
- traverseSkippingEdgesAndEffects(object, true, (child) => {
86
+ eachNode(object, (child) => {
75
87
  if (child.material) {
76
88
  const oldInstance = child.userData[MATERIAL_INSTANCE_KEY];
77
89
  if (oldInstance) {
@@ -1 +1 @@
1
- {"version":3,"file":"useOrbitTargetFollow.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrbitTargetFollow.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAsE/E,wBAAgB,oBAAoB,CAChC,WAAW,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,EACxC,YAAY,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,EAClD,YAAY,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS;AAClD,+EAA+E;AAC/E,YAAY,EAAE,MAAM,OAAO;AAC3B,4FAA4F;AAC5F,QAAQ,EAAE,OAAO;AACjB,gFAAgF;AAChF,QAAQ,EAAE,cAAc,QAqE3B;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"useOrbitTargetFollow.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrbitTargetFollow.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAsE/E,wBAAgB,oBAAoB,CAChC,WAAW,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,EACxC,YAAY,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,EAClD,YAAY,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS;AAClD,+EAA+E;AAC/E,YAAY,EAAE,MAAM,OAAO;AAC3B,4FAA4F;AAC5F,QAAQ,EAAE,OAAO;AACjB,gFAAgF;AAChF,QAAQ,EAAE,cAAc,QAsE3B;AAED,eAAe,oBAAoB,CAAC"}
@@ -34,7 +34,8 @@
34
34
  // So while looking at an object, the limits are widened each frame just enough to hold
35
35
  // where the camera is now: the object can take the view outside the authored range,
36
36
  // the user still can't rotate / zoom further out of it, and moving back in tightens
37
- // them to the authored values again. The authored values come from `controls`.
37
+ // them to the authored values again. The authored values are `controls.authoredLimits` on
38
+ // the live instance (CameraController sets them, controllers drag them), else the config.
38
39
  //
39
40
  // Height limits (controls.minHeight / maxHeight) are world Y, not relative to the target,
40
41
  // and are applied after everything else in the frame.
@@ -173,8 +174,9 @@ authored) {
173
174
  }
174
175
  // HEIGHT LIMITS (world Y): last, so nothing — user, target, follow, a clip — ends
175
176
  // the frame under the floor or over the ceiling. The camera keeps facing the target.
176
- const minH = typeof auth.minHeight === 'number' ? auth.minHeight : -Infinity;
177
- const maxH = typeof auth.maxHeight === 'number' ? auth.maxHeight : Infinity;
177
+ const lim = controls?.authoredLimits ?? auth;
178
+ const minH = typeof lim.minHeight === 'number' ? lim.minHeight : -Infinity;
179
+ const maxH = typeof lim.maxHeight === 'number' ? lim.maxHeight : Infinity;
178
180
  const y = Math.min(maxH, Math.max(minH, camera.position.y));
179
181
  if (y !== camera.position.y) {
180
182
  camera.position.y = y;
@@ -186,7 +188,7 @@ authored) {
186
188
  camera.updateMatrixWorld();
187
189
  // Limits hold the camera where the moving target left it (see the header).
188
190
  if (tObj && controls && a.locked)
189
- widenLimits(controls, camera.position, auth);
191
+ widenLimits(controls, camera.position, controls.authoredLimits ?? auth);
190
192
  };
191
193
  return () => { scene.onBeforeRender = prev; };
192
194
  }, [scene, camera, controlsRef]);
@@ -0,0 +1,36 @@
1
+ import type { ActionSequence, SceneCommand } from '@3driseai/3drise-core';
2
+ import type { OperationParams } from './types';
3
+ /** What a project holds (the lists SceneBuilder / the studio render with). */
4
+ export interface BakeSource {
5
+ objects?: ReadonlyArray<any>;
6
+ actions?: ReadonlyArray<ActionSequence>;
7
+ clips?: ReadonlyArray<{
8
+ cues?: ReadonlyArray<{
9
+ command?: SceneCommand | null;
10
+ }>;
11
+ }>;
12
+ sequences?: ReadonlyArray<{
13
+ cues?: ReadonlyArray<{
14
+ command?: SceneCommand | null;
15
+ }>;
16
+ }>;
17
+ }
18
+ /** One thing to warm: an operation with its parameters on target ids ('self' already resolved). */
19
+ interface BakeJob {
20
+ op: string;
21
+ params: OperationParams;
22
+ targets: string[];
23
+ meshNames?: Record<string, string[]>;
24
+ }
25
+ /** Every warm job of a project. */
26
+ export declare function collectBakeJobs(src: BakeSource): BakeJob[];
27
+ /** The project the scene renders (ObjectsRenderer keeps it current). */
28
+ export declare const setBakeSource: (src: BakeSource) => void;
29
+ export interface BakeReport {
30
+ jobs: number;
31
+ ms: number;
32
+ }
33
+ /** Bake the current project now (queued behind a bake that is running). Resolves when done. */
34
+ export declare function bakeProject(src?: BakeSource): Promise<BakeReport>;
35
+ export {};
36
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../src/operations/bake.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,cAAc,EAA6C,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAKrH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACvB,OAAO,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,CAAC,EAAE,aAAa,CAAC;YAAE,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IACnF,SAAS,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,CAAC,EAAE,aAAa,CAAC;YAAE,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED,mGAAmG;AACnG,UAAU,OAAO;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACxC;AASD,mCAAmC;AACnC,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,EAAE,CAyC1D;AAiBD,wEAAwE;AACxE,eAAO,MAAM,aAAa,GAAI,KAAK,UAAU,SAAsB,CAAC;AAIpE,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AAExD,+FAA+F;AAC/F,wBAAgB,WAAW,CAAC,GAAG,GAAE,UAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkBzE"}
@@ -0,0 +1,113 @@
1
+ import { findNodesByName, objectEffectClipOf } from '@3driseai/3drise-core';
2
+ import { findById } from '../utils/sceneQuery.js';
3
+ import { getOperation, resolveParams } from './registry.js';
4
+ import { getEffectClipTemplate, isWarmable, warmEffectOn } from './runtime.js';
5
+ import { objectEffectParams } from './objectEffects.js';
6
+ const commandsOfInteraction = (ix) => (Array.isArray(ix?.commands) ? ix.commands : []);
7
+ const commandsOfAction = (a) => (Array.isArray(a?.commands) ? a.commands : []);
8
+ /** The effects of an effect clip (template or an object's own): Base and every step. */
9
+ const clipEffects = (clip) => [...(clip?.effects ?? []), ...(clip?.steps ?? []).flatMap(s => s?.effects ?? [])].filter(e => e && typeof e.operation === 'string');
10
+ /** Every warm job of a project. */
11
+ export function collectBakeJobs(src) {
12
+ const jobs = new Map();
13
+ const add = (op, params, targets, meshNames) => {
14
+ if (!targets.length)
15
+ return;
16
+ const k = JSON.stringify([op, params, targets, meshNames ?? null]);
17
+ if (!jobs.has(k))
18
+ jobs.set(k, { op, params, targets, ...(meshNames ? { meshNames } : {}) });
19
+ };
20
+ const objectRow = (e, targets, meshNames) => {
21
+ const def = getOperation(e.operation);
22
+ if (!isWarmable(def))
23
+ return;
24
+ add(def.value, objectEffectParams(def, e), targets, meshNames);
25
+ };
26
+ const fromCommand = (c, selfId) => {
27
+ if (!c)
28
+ return;
29
+ const ids = (list) => (list ?? []).map(t => (t === 'self' ? selfId : t)).filter((t) => !!t);
30
+ if (c.kind === 'effect') {
31
+ const e = c.effect;
32
+ if (!e || e.enabled === false)
33
+ return;
34
+ const def = getOperation(e.operation);
35
+ if (!isWarmable(def))
36
+ return;
37
+ add(def.value, resolveParams(def, e.params), ids(e.targets), e.meshNames);
38
+ }
39
+ else if (c.kind === 'effectClip') {
40
+ const use = c.use;
41
+ const clip = use && getEffectClipTemplate(use.clip);
42
+ if (!clip)
43
+ return;
44
+ for (const e of clipEffects(clip))
45
+ objectRow(e, ids(use.targets), use.meshNames);
46
+ }
47
+ };
48
+ for (const o of src.objects ?? []) {
49
+ if (!o?.id)
50
+ continue;
51
+ for (const ix of (Array.isArray(o.actions) ? o.actions : [])) {
52
+ if (ix?.enabled === false)
53
+ continue;
54
+ for (const c of commandsOfInteraction(ix))
55
+ fromCommand(c, o.id);
56
+ }
57
+ const own = objectEffectClipOf(o);
58
+ const parts = own.parts?.length ? { [o.id]: own.parts } : undefined;
59
+ for (const e of clipEffects(own))
60
+ objectRow(e, [o.id], parts);
61
+ }
62
+ for (const a of src.actions ?? [])
63
+ for (const c of commandsOfAction(a))
64
+ fromCommand(c, null);
65
+ for (const t of [...(src.clips ?? []), ...(src.sequences ?? [])])
66
+ for (const cue of t?.cues ?? [])
67
+ fromCommand(cue?.command, null);
68
+ return [...jobs.values()];
69
+ }
70
+ function targetsOf(job) {
71
+ const out = [];
72
+ for (const id of job.targets) {
73
+ const root = findById(id);
74
+ if (!root)
75
+ continue;
76
+ const names = job.meshNames?.[id];
77
+ if (names?.length)
78
+ for (const n of names)
79
+ out.push(...findNodesByName(root, n).filter((x) => x !== root));
80
+ else
81
+ out.push(root);
82
+ }
83
+ return out;
84
+ }
85
+ // ---------------------------------------------------------------- running it
86
+ let source = {};
87
+ /** The project the scene renders (ObjectsRenderer keeps it current). */
88
+ export const setBakeSource = (src) => { source = src; };
89
+ let running = null;
90
+ /** Bake the current project now (queued behind a bake that is running). Resolves when done. */
91
+ export function bakeProject(src = source) {
92
+ if (running)
93
+ return running.then(() => bakeProject(src));
94
+ const run = (async () => {
95
+ const t0 = performance.now();
96
+ const jobs = collectBakeJobs(src);
97
+ for (const job of jobs) {
98
+ const def = getOperation(job.op);
99
+ if (!def)
100
+ continue;
101
+ const targets = targetsOf(job);
102
+ if (targets.length)
103
+ await warmEffectOn(def, targets, job.params);
104
+ // let a frame through between jobs (the studio is live while it bakes)
105
+ await new Promise(r => setTimeout(r, 0));
106
+ }
107
+ return { jobs: jobs.length, ms: Math.round(performance.now() - t0) };
108
+ })();
109
+ running = run;
110
+ void run.finally(() => { if (running === run)
111
+ running = null; });
112
+ return run;
113
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"physicalHeld.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/physicalHeld.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAqB,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAE9E,MAAM,WAAW,SAAS,CAAC,CAAC;IACxB,6CAA6C;IAC7C,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnB,gEAAgE;IAChE,CAAC,EAAE,eAAe,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,GAAG,EAAE,CAAC,CAAC;IACP,oCAAoC;IACpC,GAAG,EAAE,OAAO,CAAC;IACb,kFAAkF;IAClF,CAAC,EAAE,MAAM,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC3C,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iGAAiG;IACjG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,KAAK,CAAC,CAAC;IACjD,oHAAoH;IACpH,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,qDAAqD;IACrD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACtC;AAED,gCAAgC;AAChC,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,kBAAkB,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAgL,CAAC;AAEtP,gGAAgG;AAChG,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,WAAgD,CAAC;AAE9F,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAmD9E"}
1
+ {"version":3,"file":"physicalHeld.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/physicalHeld.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAqB,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAE9E,MAAM,WAAW,SAAS,CAAC,CAAC;IACxB,6CAA6C;IAC7C,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnB,gEAAgE;IAChE,CAAC,EAAE,eAAe,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,GAAG,EAAE,CAAC,CAAC;IACP,oCAAoC;IACpC,GAAG,EAAE,OAAO,CAAC;IACb,kFAAkF;IAClF,CAAC,EAAE,MAAM,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC3C,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iGAAiG;IACjG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,KAAK,CAAC,CAAC;IACjD,oHAAoH;IACpH,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,qDAAqD;IACrD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACtC;AAED,gCAAgC;AAChC,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,kBAAkB,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAgL,CAAC;AAEtP,gGAAgG;AAChG,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,WAAgD,CAAC;AAE9F,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAwD9E"}
@@ -62,6 +62,12 @@ export function heldPhysical(spec) {
62
62
  st.out = false;
63
63
  return run(target, st, 1, easeTime(p));
64
64
  },
65
+ // a motion reads its params every frame: a new speed / height just takes over
66
+ live(target, p) {
67
+ const st = target.userData[KEY];
68
+ if (st)
69
+ st.p = { ...p, __backward: st.p.__backward };
70
+ },
65
71
  revert(target, p) {
66
72
  const st = target.userData[KEY];
67
73
  if (!st)
@@ -34,7 +34,7 @@
34
34
  // three keeps covers every cached program.
35
35
  //
36
36
  import { Color, Group, InstancedMesh, Material as ThreeMaterial, Mesh, SkinnedMesh } from 'three';
37
- import { compileInBackground, warmContext } from './warmup.js';
37
+ import { asInFrame, compileInBackground, warmContext } from './warmup.js';
38
38
  /** material → uniform name → the live uniform object of the current layer */
39
39
  const liveUniforms = new WeakMap();
40
40
  /** material → uniform name → the stable proxy handed to the compiled program */
@@ -170,7 +170,7 @@ export async function commitPendingLayers(root) {
170
170
  if (ctx) {
171
171
  // let the live materials take the cached programs before the clones let go of them
172
172
  try {
173
- ctx.gl.compile(root, ctx.cam, ctx.scene);
173
+ asInFrame(ctx, () => ctx.gl.compile(root, ctx.cam, ctx.scene));
174
174
  }
175
175
  catch { /* next frame will */ }
176
176
  setTimeout(() => clones.forEach(c => c.dispose()), 1500);
@@ -5,12 +5,34 @@ export interface WarmContext {
5
5
  cam: any;
6
6
  }
7
7
  export declare function warmContext(): WarmContext | null;
8
+ /** Run a compile with the render target the scene is drawn into bound (see the header). */
9
+ export declare function asInFrame<T>(ctx: WarmContext, fn: () => T): T;
8
10
  /** compileAsync with a safety timeout (a driver that never reports ready must not hang an effect). */
9
- export declare function compileInBackground(root: Object3D, timeoutMs?: number): Promise<void>;
11
+ export declare function compileInBackground(root: Object3D, timeoutMs?: number, given?: WarmContext | null): Promise<void>;
12
+ /** The whole scene, as the frame draws it (the published scene's load: see triggers/readiness). */
13
+ export declare function compileScene(three?: {
14
+ gl: any;
15
+ scene: any;
16
+ camera: any;
17
+ } | null, timeoutMs?: number): Promise<void>;
18
+ /**
19
+ * Upload every texture of `root` to the GPU now. three uploads a texture the first time
20
+ * something using it is drawn — in that frame: an object hidden at load and shown later
21
+ * (a cue, an action, visibility) would stall the frame it appears in.
22
+ */
23
+ export declare function uploadTextures(root?: Object3D): number;
10
24
  /** Keep a freshly created helper off screen until its shaders are compiled (see warmHelpers). */
11
25
  export declare function hideUntilWarm(obj: Object3D): void;
12
26
  /** Compile every helper under `root` that is waiting, in the background, then show it. */
13
27
  export declare function warmHelpers(root: Object3D): Promise<void>;
28
+ /**
29
+ * The shadow pass draws a shadow caster with three's own depth material — a program
30
+ * compileAsync never builds, so a new kind of caster (an instanced helper) compiled it
31
+ * in the first frame that drew its shadow. Build it here: a stand-in of the same kind
32
+ * with an equivalent depth material, compiled into a render target as the shadow map is.
33
+ * The stand-ins are kept (never drawn) so the programs stay cached.
34
+ */
35
+ export declare function warmShadowPass(root: Object3D): Promise<void>;
14
36
  /**
15
37
  * Warm-only runs (pre-warming): while this is on, an effect's runProgress compiles
16
38
  * everything it needs and then stops — nothing animates. See runtime.prewarmEffect.
@@ -1 +1 @@
1
- {"version":3,"file":"warmup.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/warmup.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGhD,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAAE;AAE9D,wBAAgB,WAAW,IAAI,WAAW,GAAG,IAAI,CAGhD;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQnF;AAUD,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,QAI1C;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzD;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ;;CAAgB,CAAC;AAStC,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,QAmB5C"}
1
+ {"version":3,"file":"warmup.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/warmup.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAY,QAAQ,EAAW,MAAM,OAAO,CAAC;AAGzD,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAAE;AAE9D,wBAAgB,WAAW,IAAI,WAAW,GAAG,IAAI,CAIhD;AA4BD,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAO7D;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,SAAO,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/G;AAED,mGAAmG;AACnG,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE;IAAE,EAAE,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GAAG,IAAI,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjH;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAatD;AAWD,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,QAI1C;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzD;AAsBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5D;AAyCD;;;GAGG;AACH,eAAO,MAAM,QAAQ;;CAAgB,CAAC;AAStC,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,QAqB5C"}