@3driseai/3drise-viewer 0.1.38 → 0.1.40

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 (32) hide show
  1. package/dist/animationsV2/ClipsRuntime.d.ts +30 -0
  2. package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
  3. package/dist/animationsV2/ClipsRuntime.js +177 -10
  4. package/dist/animationsV2/clipUtils.d.ts +6 -0
  5. package/dist/animationsV2/clipUtils.d.ts.map +1 -1
  6. package/dist/animationsV2/clipUtils.js +28 -0
  7. package/dist/animationsV2/normalize.d.ts.map +1 -1
  8. package/dist/animationsV2/normalize.js +6 -1
  9. package/dist/animationsV2/types.d.ts +8 -0
  10. package/dist/animationsV2/types.d.ts.map +1 -1
  11. package/dist/components/AnimatedObject.d.ts.map +1 -1
  12. package/dist/components/AnimatedObject.js +6 -2
  13. package/dist/components/EnabledContext.d.ts +12 -0
  14. package/dist/components/EnabledContext.d.ts.map +1 -0
  15. package/dist/components/EnabledContext.js +12 -0
  16. package/dist/components/ObjectNode.d.ts.map +1 -1
  17. package/dist/components/ObjectNode.js +6 -1
  18. package/dist/components/ObjectsRenderer.d.ts.map +1 -1
  19. package/dist/components/ObjectsRenderer.js +9 -0
  20. package/dist/constants.d.ts +1 -1
  21. package/dist/constants.d.ts.map +1 -1
  22. package/dist/constants.js +16 -5
  23. package/dist/operations/catalogue/motionTrail.d.ts.map +1 -1
  24. package/dist/operations/catalogue/motionTrail.js +8 -1
  25. package/dist/ui/UiAnchorUpdater.d.ts.map +1 -1
  26. package/dist/ui/UiAnchorUpdater.js +2 -1
  27. package/dist/utils/cursorPicking.d.ts.map +1 -1
  28. package/dist/utils/cursorPicking.js +2 -1
  29. package/dist/utils/shownInScene.d.ts +13 -0
  30. package/dist/utils/shownInScene.d.ts.map +1 -0
  31. package/dist/utils/shownInScene.js +16 -0
  32. package/package.json +1 -1
@@ -18,6 +18,16 @@ export interface RuntimeEvent {
18
18
  }
19
19
  /** @deprecated name kept for existing imports */
20
20
  export type ClipEvent = RuntimeEvent;
21
+ /**
22
+ * Blends: a property never jumps when a driver takes it over or lets it go. When a continuous
23
+ * track first wins a property, the runtime remembers where the property IS (the last value it
24
+ * wrote, else the live value, else the authored one) and for `blend` seconds writes a mix from
25
+ * there to the track's value; when every driver lets the property go, it glides back to the
26
+ * authored value the same way. So a project whose saved objects sit elsewhere than a sequence's
27
+ * first keys, a sequence first posed mid-way (a scroll story on a reload), a clip started while
28
+ * another one holds the property, or a clip stopped mid-move - none of them cut.
29
+ */
30
+ export declare const DEFAULT_BLEND = 0.35;
21
31
  /**
22
32
  * How a cue switches (apply / revert) or fires its subject. The triggers engine installs one,
23
33
  * so cues run through it with the clip or sequence as their source. Returns false when an
@@ -46,6 +56,21 @@ declare class ClipsRuntime {
46
56
  private eventListeners;
47
57
  /** tracks whose authored value must be written back on the next tick */
48
58
  private pendingRestore;
59
+ /** Blend-ins in flight, per property (see Blend). */
60
+ private blends;
61
+ /** Blend-outs in flight, per property: written by the tick until done. */
62
+ private blendOuts;
63
+ /** Runtime seconds (frame deltas), the clock the blends run on. */
64
+ private clock;
65
+ /** Blend seconds of the driver that last wrote each property (for its blend-out). */
66
+ private blendOf;
67
+ /** Next tick writes every winner even if unchanged (an edited clip). */
68
+ private forceWrite;
69
+ /** Diagnostics: keys written last tick, and keys written for the FIRST time last tick. */
70
+ private lastWritten;
71
+ private lastFirstWrites;
72
+ private everWritten;
73
+ private tickCost;
49
74
  /** last written value per property (targetKey -> JSON) */
50
75
  private written;
51
76
  /** Discrete values laid last tick, per element (JSON) — to see which elements changed. */
@@ -70,6 +95,11 @@ declare class ClipsRuntime {
70
95
  setLiveValue(state: string, path: string, value: KeyValue, node?: string): boolean;
71
96
  /** What was last written by `setLiveValue`, else the authored value (action patches included). */
72
97
  getLiveValue(state: string, path: string, node?: string): KeyValue | undefined;
98
+ /** Diagnostics: a write whose speed differs sharply from the previous frame's (a velocity discontinuity), per property. */
99
+ private lastSpeed;
100
+ private probeJump;
101
+ /** Where a property is right now: the last value the runtime wrote, else the live / authored value. */
102
+ private currentValue;
73
103
  /** Whether `setLiveValue` can write this path (it has an applier). */
74
104
  canSetLiveValue(state: string, path: string): boolean;
75
105
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ClipsRuntime.d.ts","sourceRoot":"","sources":["../../src/animationsV2/ClipsRuntime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ClipsRuntime.d.ts","sourceRoot":"","sources":["../../src/animationsV2/ClipsRuntime.ts"],"names":[],"mappings":"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"}
@@ -42,11 +42,35 @@
42
42
  import { SceneActions, expandMaterialVariant } from '@3driseai/3drise-core';
43
43
  import { logTrigger } from '../triggers/log.js';
44
44
  import { getAtPath, sampleTrack } from './clipUtils.js';
45
+ import { interpolateValue } from '@3driseai/3drise-core';
45
46
  import { applyValue, clearApplierCaches, isApplicable, isTargetMounted, releaseLive } from './appliers.js';
46
47
  import { readNodeValue, restoreNodeTrack } from './nodeTracks.js';
47
48
  import { cueStatesAt, entryLocalTime, isEntryActive, resolveSequence, cueCommand, clipCueSchedule, firedBetween, } from './sequenceUtils.js';
48
49
  /** Longest an autoplaying sequence waits for its targets. */
49
50
  const MAX_TARGET_WAIT_MS = 8000;
51
+ /**
52
+ * Blends: a property never jumps when a driver takes it over or lets it go. When a continuous
53
+ * track first wins a property, the runtime remembers where the property IS (the last value it
54
+ * wrote, else the live value, else the authored one) and for `blend` seconds writes a mix from
55
+ * there to the track's value; when every driver lets the property go, it glides back to the
56
+ * authored value the same way. So a project whose saved objects sit elsewhere than a sequence's
57
+ * first keys, a sequence first posed mid-way (a scroll story on a reload), a clip started while
58
+ * another one holds the property, or a clip stopped mid-move - none of them cut.
59
+ */
60
+ export const DEFAULT_BLEND = 0.35;
61
+ const smooth = (t) => t * t * (3 - 2 * t);
62
+ const canBlend = (v) => typeof v === 'number' || (typeof v === 'string' && /^#[0-9a-f]{6}$/i.test(v)) || (Array.isArray(v) && v.every(x => typeof x === 'number'));
63
+ function mixValues(path, a, b, p) {
64
+ if (p <= 0)
65
+ return a;
66
+ if (p >= 1)
67
+ return b;
68
+ if (!canBlend(a) || !canBlend(b) || typeof a !== typeof b || (Array.isArray(a) !== Array.isArray(b)))
69
+ return b;
70
+ if (Array.isArray(a) && Array.isArray(b) && a.length !== b.length)
71
+ return b;
72
+ return interpolateValue(path.split('.').pop() ?? path, a, b, p);
73
+ }
50
74
  /** The SceneActions layer discrete tracks are set through. */
51
75
  const TIMELINE_LAYER = 'timeline';
52
76
  /** Frames a changed element's continuous tracks are re-written for (its re-render may rebuild their target). */
@@ -81,6 +105,21 @@ class ClipsRuntime {
81
105
  eventListeners = new Set();
82
106
  /** tracks whose authored value must be written back on the next tick */
83
107
  pendingRestore = [];
108
+ /** Blend-ins in flight, per property (see Blend). */
109
+ blends = new Map();
110
+ /** Blend-outs in flight, per property: written by the tick until done. */
111
+ blendOuts = new Map();
112
+ /** Runtime seconds (frame deltas), the clock the blends run on. */
113
+ clock = 0;
114
+ /** Blend seconds of the driver that last wrote each property (for its blend-out). */
115
+ blendOf = new Map();
116
+ /** Next tick writes every winner even if unchanged (an edited clip). */
117
+ forceWrite = false;
118
+ /** Diagnostics: keys written last tick, and keys written for the FIRST time last tick. */
119
+ lastWritten = [];
120
+ lastFirstWrites = [];
121
+ everWritten = new Set();
122
+ tickCost = 0;
84
123
  /** last written value per property (targetKey -> JSON) */
85
124
  written = new Map();
86
125
  /** Discrete values laid last tick, per element (JSON) — to see which elements changed. */
@@ -150,6 +189,49 @@ class ClipsRuntime {
150
189
  return undefined;
151
190
  return getAtPath(this.ctx.getSettings(state), path);
152
191
  }
192
+ /** Diagnostics: a write whose speed differs sharply from the previous frame's (a velocity discontinuity), per property. */
193
+ lastSpeed = new Map();
194
+ probeJump(key, prevJson, value, dt) {
195
+ if (prevJson === undefined)
196
+ return;
197
+ let prev;
198
+ try {
199
+ prev = JSON.parse(prevJson);
200
+ }
201
+ catch {
202
+ return;
203
+ }
204
+ const num = (v) => typeof v === 'number' ? [v] : Array.isArray(v) && v.every(x => typeof x === 'number') ? v : null;
205
+ const a = num(prev), b = num(value);
206
+ if (!a || !b || a.length !== b.length || dt <= 0)
207
+ return;
208
+ const d = Math.max(...a.map((x, i) => Math.abs(b[i] - x)));
209
+ const speed = d / dt;
210
+ const last = this.lastSpeed.get(key);
211
+ this.lastSpeed.set(key, speed);
212
+ if (last === undefined || last < 1e-4)
213
+ return;
214
+ const ratio = speed / last;
215
+ if (ratio > 2.5 || ratio < 0.4)
216
+ this.dlog('JUMP', key, { from: prev, to: value, speedWas: +last.toFixed(4), speedNow: +speed.toFixed(4), dt: +dt.toFixed(4), at: this.clock.toFixed(3) });
217
+ }
218
+ /** Where a property is right now: the last value the runtime wrote, else the live / authored value. */
219
+ currentValue(state, path, node) {
220
+ const key = targetKey(state, node, path);
221
+ const out = this.blendOuts.get(key);
222
+ if (out) {
223
+ const u = out.duration > 0 ? (this.clock - out.start) / out.duration : 1;
224
+ return mixValues(path, out.from, out.to, smooth(Math.min(1, u)));
225
+ }
226
+ const w = this.written.get(key);
227
+ if (w !== undefined) {
228
+ try {
229
+ return JSON.parse(w);
230
+ }
231
+ catch { /* fall through */ }
232
+ }
233
+ return this.getLiveValue(state, path, node);
234
+ }
153
235
  /** Whether `setLiveValue` can write this path (it has an applier). */
154
236
  canSetLiveValue(state, path) {
155
237
  return isApplicable(state, path);
@@ -219,6 +301,9 @@ class ClipsRuntime {
219
301
  this.clips.clear();
220
302
  this.sequences.clear();
221
303
  this.pendingRestore = [];
304
+ this.blends.clear();
305
+ this.blendOuts.clear();
306
+ this.blendOf.clear();
222
307
  this.written.clear();
223
308
  this.laid.clear();
224
309
  this.rewrite.clear();
@@ -294,7 +379,7 @@ class ClipsRuntime {
294
379
  this.pendingRestore.push(...removed);
295
380
  inst.clip = clip;
296
381
  inst.time = Math.min(inst.time, clip.duration);
297
- this.written.clear(); // values may have changed under the same time
382
+ this.forceWrite = true; // values may have changed under the same time (the written marks stay: no spurious blend-ins)
298
383
  this.bumpState();
299
384
  }
300
385
  /**
@@ -518,6 +603,17 @@ class ClipsRuntime {
518
603
  return;
519
604
  }
520
605
  const dt = Math.min(delta, 0.1);
606
+ this.clock += dt;
607
+ const tickStart = this.debug ? performance.now() : 0;
608
+ if (this.debug) {
609
+ const t = this.tickCost;
610
+ if (t > 8)
611
+ this.dlog('slow tick (previous)', { ms: +t.toFixed(1), at: this.clock.toFixed(3) });
612
+ }
613
+ if (this.debug && delta > 0.028)
614
+ this.dlog('long frame', { delta: +delta.toFixed(3), at: this.clock.toFixed(3), writtenLastTick: this.lastWritten.slice(0, 40), firstWrites: this.lastFirstWrites });
615
+ this.lastWritten = [];
616
+ this.lastFirstWrites = [];
521
617
  let anyPlaying = false;
522
618
  for (const inst of [...this.clips.values()]) {
523
619
  const prev = inst.time;
@@ -601,22 +697,70 @@ class ClipsRuntime {
601
697
  else
602
698
  this.laid.delete(state);
603
699
  this.rewrite.set(state, REWRITE_FRAMES);
700
+ this.dlog('layer changed (element re-renders)', state, { at: this.clock.toFixed(3), patch: layer[state] });
604
701
  // Switch tracks over an action / Change cue setting the same thing: reported, not resolved.
605
702
  if (json)
606
703
  this.noteLayerClash(state, layer[state]);
607
704
  }
608
705
  SceneActions.setLayer(TIMELINE_LAYER, layer);
706
+ // Released properties gliding back to authored (a winner for the same property takes over).
707
+ for (const [key, b] of this.blendOuts) {
708
+ if (winners.has(key)) {
709
+ this.blendOuts.delete(key);
710
+ continue;
711
+ }
712
+ const u = b.duration > 0 ? (this.clock - b.start) / b.duration : 1;
713
+ const v = mixValues(b.path, b.from, b.to, smooth(Math.min(1, u)));
714
+ applyValue(ctx, b.state, b.path, v, b.node);
715
+ if (u >= 1)
716
+ this.blendOuts.delete(key);
717
+ }
609
718
  const failed = [];
610
719
  for (const [key, p] of winners) {
611
720
  if (p.discrete)
612
721
  continue;
613
- const json = JSON.stringify(p.value);
614
- if (this.written.get(key) === json && !this.rewrite.has(p.state))
722
+ // A driver taking the property over: start it from where the property is, not from the key.
723
+ let blend = this.blends.get(key);
724
+ if (!this.written.has(key)) {
725
+ const duration = p.blend ?? DEFAULT_BLEND;
726
+ const from = this.currentValue(p.state, p.path, p.node);
727
+ if (duration > 0 && from !== undefined && JSON.stringify(from) !== JSON.stringify(p.value)) {
728
+ blend = { from, start: this.clock, duration };
729
+ this.blends.set(key, blend);
730
+ this.dlog('blend in', key, { from, to: p.value, duration });
731
+ }
732
+ else {
733
+ this.blends.delete(key);
734
+ blend = undefined;
735
+ if (this.debug)
736
+ this.dlogEvery('noblend:' + key, 2000, 'no blend', key, { duration, from, to: p.value });
737
+ }
738
+ }
739
+ let value = p.value;
740
+ if (blend) {
741
+ const u = (this.clock - blend.start) / blend.duration;
742
+ if (u >= 1)
743
+ this.blends.delete(key);
744
+ else
745
+ value = mixValues(p.path, blend.from, p.value, smooth(u));
746
+ }
747
+ const json = JSON.stringify(value);
748
+ if (!this.forceWrite && this.written.get(key) === json && !this.rewrite.has(p.state))
615
749
  continue;
616
750
  // Recorded only when it landed: a target that is not mounted yet (a model still
617
751
  // loading) is retried next frame instead of being skipped for good.
618
- if (applyValue(ctx, p.state, p.path, p.value, p.node))
752
+ if (this.debug) {
753
+ this.probeJump(key, this.written.get(key), value, dt);
754
+ this.lastWritten.push(key + '=' + json.slice(0, 24));
755
+ if (!this.everWritten.has(key)) {
756
+ this.everWritten.add(key);
757
+ this.lastFirstWrites.push(key);
758
+ }
759
+ }
760
+ if (applyValue(ctx, p.state, p.path, value, p.node)) {
619
761
  this.written.set(key, json);
762
+ this.blendOf.set(key, p.blend ?? DEFAULT_BLEND);
763
+ }
620
764
  else if (this.debug)
621
765
  failed.push(key);
622
766
  }
@@ -628,6 +772,9 @@ class ClipsRuntime {
628
772
  else
629
773
  this.rewrite.set(state, n - 1);
630
774
  }
775
+ this.forceWrite = false;
776
+ if (this.debug)
777
+ this.tickCost = performance.now() - tickStart;
631
778
  if (anyPlaying)
632
779
  this.bump();
633
780
  }
@@ -781,7 +928,7 @@ class ClipsRuntime {
781
928
  *proposals() {
782
929
  const drivers = [];
783
930
  for (const inst of this.clips.values()) {
784
- drivers.push({ order: inst.order, run: () => sampleTracks(inst.clip.tracks, inst.time) });
931
+ drivers.push({ order: inst.order, run: () => sampleTracks(inst.clip.tracks, inst.time, inst.clip.blend ?? DEFAULT_BLEND) });
785
932
  }
786
933
  for (const inst of this.sequences.values()) {
787
934
  drivers.push({
@@ -790,7 +937,7 @@ class ClipsRuntime {
790
937
  for (const e of inst.schedule.entries) {
791
938
  if (!inst.active.has(e.id))
792
939
  continue;
793
- yield* sampleTracks(e.clip.tracks, entryLocalTime(e, inst.time));
940
+ yield* sampleTracks(e.clip.tracks, entryLocalTime(e, inst.time), e.clip.blend ?? inst.seq.blend ?? DEFAULT_BLEND);
794
941
  }
795
942
  },
796
943
  });
@@ -810,7 +957,9 @@ class ClipsRuntime {
810
957
  if (done.has(key))
811
958
  continue;
812
959
  done.add(key);
960
+ const last = this.written.get(key);
813
961
  this.written.delete(key);
962
+ this.blends.delete(key);
814
963
  if (track.node) {
815
964
  // Node tracks restore their exact pre-animation snapshot (see nodeTracks).
816
965
  const node = track.node;
@@ -821,10 +970,28 @@ class ClipsRuntime {
821
970
  // (another driver re-writes it this frame).
822
971
  if (releaseLive(track.state, track.path))
823
972
  continue;
824
- // Another driver may still own this property; it re-writes this frame.
973
+ // Another driver may still own this property; it re-writes this frame. Otherwise it glides
974
+ // back to the authored value (blend-out) instead of cutting.
825
975
  const authored = getAtPath(ctx.getSettings(track.state), track.path);
826
- if (authored !== undefined)
976
+ if (authored === undefined)
977
+ continue;
978
+ const duration = this.blendOf.get(key) ?? DEFAULT_BLEND;
979
+ let from;
980
+ if (last !== undefined) {
981
+ try {
982
+ from = JSON.parse(last);
983
+ }
984
+ catch {
985
+ from = undefined;
986
+ }
987
+ }
988
+ if (duration > 0 && from !== undefined && canBlend(from) && canBlend(authored) && JSON.stringify(from) !== JSON.stringify(authored)) {
989
+ this.blendOuts.set(key, { state: track.state, path: track.path, from, to: authored, start: this.clock, duration });
990
+ }
991
+ else {
992
+ this.blendOuts.delete(key);
827
993
  applyValue(ctx, track.state, track.path, authored);
994
+ }
828
995
  }
829
996
  }
830
997
  /** Whether any active driver still has a track on (state, node, path). */
@@ -963,14 +1130,14 @@ class ClipsRuntime {
963
1130
  }
964
1131
  const round2 = (n) => Math.round(n * 100) / 100;
965
1132
  const isDriven = (seq) => !!seq.driver && seq.driver !== 'time';
966
- function* sampleTracks(tracks, t) {
1133
+ function* sampleTracks(tracks, t, blend) {
967
1134
  for (const track of tracks) {
968
1135
  if (track.muted || track.keys.length === 0)
969
1136
  continue;
970
1137
  const value = sampleTrack(track, t);
971
1138
  if (value === undefined)
972
1139
  continue;
973
- yield { state: track.state, node: track.node, path: track.path, value, discrete: !!track.discrete };
1140
+ yield { state: track.state, node: track.node, path: track.path, value, discrete: !!track.discrete, blend };
974
1141
  }
975
1142
  }
976
1143
  const clipsRuntime = new ClipsRuntime();
@@ -18,6 +18,12 @@ export declare const sortKeys: (keys: Keyframe[]) => Keyframe[];
18
18
  export declare function upsertKey(track: Track, t: number, value: KeyValue, fps: number): Track;
19
19
  /** Move keys by dt seconds, clamped to [0, duration], snapped to frames unless `free`. */
20
20
  export declare function moveKeys(clip: AnimationClip, selection: Set<string>, dt: number, free: boolean): AnimationClip;
21
+ /**
22
+ * Copies of the selected keys `dt` seconds away (snapped to a frame), on their own tracks; the
23
+ * originals stay. A copy landing on a key of its track replaces it. `ids` maps original → copy id
24
+ * (pass the same map while dragging so the copies keep their ids).
25
+ */
26
+ export declare function copyKeys(clip: AnimationClip, selection: Set<string>, dt: number, ids: Map<string, string>): AnimationClip;
21
27
  export declare function deleteKeys(clip: AnimationClip, selection: Set<string>): AnimationClip;
22
28
  export declare function setKeysEase(clip: AnimationClip, selection: Set<string>, ease: EaseName): AnimationClip;
23
29
  export declare function setKeyValue(clip: AnimationClip, keyId: string, value: KeyValue): AnimationClip;
@@ -1 +1 @@
1
- {"version":3,"file":"clipUtils.d.ts","sourceRoot":"","sources":["../../src/animationsV2/clipUtils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAOlF,eAAO,MAAM,GAAG,GAAI,QAAQ,MAAM,WAAqF,CAAC;AAExH,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CAOrD;AAMD,eAAO,MAAM,cAAc,GAAI,GAAG,MAAM,EAAE,KAAK,MAAM,WAAwB,CAAC;AAC9E,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,EAAE,KAAK,MAAM,WAAgB,CAAC;AAC1E,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,EAAE,KAAK,MAAM,WAAgD,CAAC;AAEnG,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKvD;AAaD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAyBzE;AAMD,eAAO,MAAM,QAAQ,GAAI,MAAM,QAAQ,EAAE,eAAwC,CAAC;AAElF,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAOtF;AAED,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,aAAa,CAc9G;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,aAAa,CAKrF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAQtG;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,aAAa,CAQ9F;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAAG,SAAS,CAMvG;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,EAAE,CAIzD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAEhE;AAED,4CAA4C;AAC5C,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAQvF"}
1
+ {"version":3,"file":"clipUtils.d.ts","sourceRoot":"","sources":["../../src/animationsV2/clipUtils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAOlF,eAAO,MAAM,GAAG,GAAI,QAAQ,MAAM,WAAqF,CAAC;AAExH,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CAOrD;AAMD,eAAO,MAAM,cAAc,GAAI,GAAG,MAAM,EAAE,KAAK,MAAM,WAAwB,CAAC;AAC9E,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,EAAE,KAAK,MAAM,WAAgB,CAAC;AAC1E,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,EAAE,KAAK,MAAM,WAAgD,CAAC;AAEnG,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKvD;AAaD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAyBzE;AAMD,eAAO,MAAM,QAAQ,GAAI,MAAM,QAAQ,EAAE,eAAwC,CAAC;AAElF,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAOtF;AAED,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,aAAa,CAc9G;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CAkBzH;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,aAAa,CAKrF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAQtG;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,aAAa,CAQ9F;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAAG,SAAS,CAMvG;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,EAAE,CAIzD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAEhE;AAED,4CAA4C;AAC5C,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAQvF"}
@@ -115,6 +115,34 @@ export function moveKeys(clip, selection, dt, free) {
115
115
  }),
116
116
  };
117
117
  }
118
+ /**
119
+ * Copies of the selected keys `dt` seconds away (snapped to a frame), on their own tracks; the
120
+ * originals stay. A copy landing on a key of its track replaces it. `ids` maps original → copy id
121
+ * (pass the same map while dragging so the copies keep their ids).
122
+ */
123
+ export function copyKeys(clip, selection, dt, ids) {
124
+ return {
125
+ ...clip,
126
+ tracks: clip.tracks.map(track => {
127
+ const picked = track.keys.filter(k => selection.has(k.id));
128
+ if (!picked.length)
129
+ return track;
130
+ const copies = picked.map(k => {
131
+ let id = ids.get(k.id);
132
+ if (!id) {
133
+ id = uid('k');
134
+ ids.set(k.id, id);
135
+ }
136
+ return { ...k, id, t: snapToFrame(Math.min(clip.duration, Math.max(0, k.t + dt)), clip.fps) };
137
+ });
138
+ const taken = new Set(copies.map(c => c.t));
139
+ // a copy on top of its own original replaces nothing (no move yet): keep the original
140
+ const kept = track.keys.filter(k => selection.has(k.id) || !taken.has(k.t));
141
+ const fresh = copies.filter(c => !picked.some(p => p.t === c.t));
142
+ return { ...track, keys: sortKeys([...kept, ...fresh]) };
143
+ }),
144
+ };
145
+ }
118
146
  export function deleteKeys(clip, selection) {
119
147
  return {
120
148
  ...clip,
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/animationsV2/normalize.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAkB,MAAM,SAAS,CAAC;AAQhF,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,aAAa,CAgBrD;AAID,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,iBAAiB,CAyC7D"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/animationsV2/normalize.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAkB,MAAM,SAAS,CAAC;AAQhF,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,aAAa,CAiBrD;AAID,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,iBAAiB,CA6C7D"}
@@ -13,10 +13,11 @@ export function normalizeClip(row) {
13
13
  loop: flag(row.loop),
14
14
  yoyo: flag(row.yoyo),
15
15
  endMode: row.endMode === 'restore' ? 'restore' : 'hold',
16
+ ...(row.blend !== undefined && row.blend !== null && Number.isFinite(Number(row.blend)) ? { blend: Math.max(0, Number(row.blend)) } : {}),
16
17
  tracks: Array.isArray(row.tracks) ? row.tracks : [],
17
18
  cues: (Array.isArray(row.cues) ? row.cues : [])
18
19
  .filter((c) => c && c.command && typeof c.command === 'object')
19
- .map((c, i) => ({ id: c.id ?? `cue-${i}`, command: c.command, at: Math.max(0, Number(c.at) || 0), mode: CUE_MODES.includes(c.mode) ? c.mode : 'apply' })),
20
+ .map((c, i) => ({ id: c.id ?? `cue-${i}`, command: c.command, at: Math.max(0, Number(c.at) || 0), mode: CUE_MODES.includes(c.mode) ? c.mode : 'apply', ...(flag(c.muted) ? { muted: true } : {}) })),
20
21
  };
21
22
  }
22
23
  const CUE_MODES = ['apply', 'revert', 'fire'];
@@ -37,6 +38,8 @@ export function normalizeSequence(row) {
37
38
  clipId: c.clipId,
38
39
  delay: Math.max(0, Number(c.delay) || 0),
39
40
  speed: Number(c.speed) > 0 ? Number(c.speed) : 1,
41
+ ...(flag(c.muted) ? { muted: true } : {}),
42
+ ...(flag(c.reverse) ? { reverse: true } : {}),
40
43
  }))
41
44
  : [],
42
45
  })),
@@ -48,11 +51,13 @@ export function normalizeSequence(row) {
48
51
  stepId: c.stepId,
49
52
  at: Math.max(0, Number(c.at) || 0),
50
53
  mode: CUE_MODES.includes(c.mode) ? c.mode : 'apply',
54
+ ...(flag(c.muted) ? { muted: true } : {}),
51
55
  })),
52
56
  loop: flag(row.loop),
53
57
  yoyo: flag(row.yoyo),
54
58
  reverse: flag(row.reverse),
55
59
  endMode: row.endMode === 'restore' ? 'restore' : 'hold',
60
+ ...(row.blend !== undefined && row.blend !== null && Number.isFinite(Number(row.blend)) ? { blend: Math.max(0, Number(row.blend)) } : {}),
56
61
  driver: DRIVERS.includes(row.driver) ? row.driver : 'time',
57
62
  driverSettings: {
58
63
  sensitivity: Number(row.driverSettings?.sensitivity) > 0 ? Number(row.driverSettings.sensitivity) : DEFAULT_DRIVER_SETTINGS.sensitivity,
@@ -47,6 +47,12 @@ export interface AnimationClip {
47
47
  yoyo: boolean;
48
48
  /** When a non-looping clip finishes: keep the last values, or return to authored. */
49
49
  endMode: 'hold' | 'restore';
50
+ /**
51
+ * Seconds a property glides from where it is to the clip's value when the clip takes it over,
52
+ * and back to the authored value when the clip lets it go (see ClipsRuntime blends). Absent: the
53
+ * runtime default (DEFAULT_BLEND). 0 = snap, as before.
54
+ */
55
+ blend?: number;
50
56
  tracks: Track[];
51
57
  /** Effects, effect clips and actions switched / fired along the clip (TimelineCue). */
52
58
  cues?: TimelineCue[];
@@ -124,6 +130,8 @@ export interface AnimationSequence {
124
130
  yoyo: boolean;
125
131
  reverse: boolean;
126
132
  endMode: 'hold' | 'restore';
133
+ /** Blend-in / out seconds for every clip in the sequence (a clip's own `blend` wins). Absent: the runtime default. */
134
+ blend?: number;
127
135
  /** What moves the clock. Input drivers scrub the sequence instead of playing it. */
128
136
  driver: SequenceDriver;
129
137
  driverSettings: SequenceDriverSettings;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/animationsV2/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/animationsV2/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AnimatedObject.d.ts","sourceRoot":"","sources":["../../src/components/AnimatedObject.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAO7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACtG,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,aAAa,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACjH,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAyFvD,CAAC;AAEH,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"AnimatedObject.d.ts","sourceRoot":"","sources":["../../src/components/AnimatedObject.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQ7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACtG,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,aAAa,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACjH,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA4FvD,CAAC;AAEH,eAAe,cAAc,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useObjectReady } from '../hooks/useObjectReady.js';
3
- import { useRef, useEffect, useCallback, useMemo, memo } from 'react';
3
+ import { useRef, useEffect, useCallback, useMemo, memo, useContext } from 'react';
4
+ import { EnabledContext } from './EnabledContext.js';
4
5
  import { objectEffectClipOf, objectEffectStepsOf, objectTakesVisualEffects, DEFAULT_EFFECT_SPREAD } from '@3driseai/3drise-core';
5
6
  import { usePathAnimation } from '../hooks/usePathAnimation.js';
6
7
  import { useObjectEffectLayers } from '../operations/useObjectEffectLayers.js';
@@ -36,8 +37,11 @@ visible = true, children, parentRef, handleObjectClick, onPointerEnter, onPointe
36
37
  // Pass the ref itself, not `groupRef.current`: the animation hooks read
37
38
  // `.current` inside useFrame, so the group resolves the moment React
38
39
  // attaches it — no scene lookup and no extra render needed.
40
+ // Disabled (hidden itself, or under a hidden group): its constant animations and mouse-move pause.
41
+ // They are time-based, so on enable they pick up where the clock is — no catch-up jump.
42
+ const enabled = useContext(EnabledContext) && visible;
39
43
  useObjectAnimation(createdObject, animateMaterial, {
40
- enabled: createdObject.type !== 'gallery', //
44
+ enabled: createdObject.type !== 'gallery' && enabled, //
41
45
  hovered,
42
46
  }, groupRef);
43
47
  // Effects layered on the object (frost, metalize…) — switched on / off, held while on.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Whether the scene object rendering here is enabled: its own `visible` AND every ancestor's.
3
+ *
4
+ * A group's enabled state overrides its children's, recursively, at runtime only — nothing is
5
+ * written to the children, so switching the group back on brings each child back to its own
6
+ * state (a child hidden on its own stays hidden). ObjectNode provides it per object (from the
7
+ * PRESENTED visibility, so a group whose effects follow its visibility plays them out before its
8
+ * children switch off); AnimatedObject reads it to pause the object's own constant animations
9
+ * and mouse-move while disabled. Pointer events skip hidden subtrees separately (shownInScene).
10
+ */
11
+ export declare const EnabledContext: import("react").Context<boolean>;
12
+ //# sourceMappingURL=EnabledContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnabledContext.d.ts","sourceRoot":"","sources":["../../src/components/EnabledContext.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,kCAAsB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { createContext } from 'react';
2
+ /**
3
+ * Whether the scene object rendering here is enabled: its own `visible` AND every ancestor's.
4
+ *
5
+ * A group's enabled state overrides its children's, recursively, at runtime only — nothing is
6
+ * written to the children, so switching the group back on brings each child back to its own
7
+ * state (a child hidden on its own stays hidden). ObjectNode provides it per object (from the
8
+ * PRESENTED visibility, so a group whose effects follow its visibility plays them out before its
9
+ * children switch off); AnimatedObject reads it to pause the object's own constant animations
10
+ * and mouse-move while disabled. Pointer events skip hidden subtrees separately (shownInScene).
11
+ */
12
+ export const EnabledContext = createContext(true);
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAe,qBAAqB,EAA2C,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACzI,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAiBrD,KAAK,eAAe,GAAG,gBAAgB,GAAG;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CAC7G,CAAC;AA4BF,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA8IzC,CAAC;AACF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAe,qBAAqB,EAA2C,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACzI,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAiBrD,KAAK,eAAe,GAAG,gBAAgB,GAAG;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CAC7G,CAAC;AA4BF,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAkJzC,CAAC;AACF,eAAe,UAAU,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useContext, useMemo } from "react";
3
3
  import { GroupMaterialContext, groupMaterialFor } from "./GroupMaterialContext.js";
4
+ import { EnabledContext } from "./EnabledContext.js";
4
5
  import CustomPrimitive from "./CustomPrimitive.js";
5
6
  import CreatedObject from "./CreatedObject.js";
6
7
  import PathRenderer from './PathRenderer.js';
@@ -66,6 +67,9 @@ const ObjectNode = ({ node, onObjectReady, onObjectDispose, handleObjectClick })
66
67
  const runtimeObject = useRuntimeSettings(node.createdObject?.id, node.createdObject);
67
68
  // An object whose effects follow its visibility stays drawn until they have played out.
68
69
  const createdObject = usePresentedVisibility(runtimeObject);
70
+ // Enabled = its own (presented) visibility and every ancestor's — see EnabledContext.
71
+ const parentEnabled = useContext(EnabledContext);
72
+ const enabled = parentEnabled && createdObject?.meshSettings?.visible !== false;
69
73
  // Children describe themselves with their own settings; the scene above
70
74
  // knows them by the node's createdObject, so relabel on the way up.
71
75
  const relabel = useCallback((obj) => ({
@@ -187,6 +191,7 @@ const ObjectNode = ({ node, onObjectReady, onObjectDispose, handleObjectClick })
187
191
  // {/* <EffectsLayer effects={createdObject.effects} /> */}
188
192
  // </>
189
193
  // : renderObject(createdObject);
190
- return renderedObject;
194
+ // Always the Provider (same element type whatever the value), so toggling never remounts the subtree.
195
+ return _jsx(EnabledContext.Provider, { value: enabled, children: renderedObject });
191
196
  };
192
197
  export default ObjectNode;
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectsRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ObjectsRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACvH,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAU9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,UAAU,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,WAAW,CAAC;IAC5B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,qBAAqB,EAAE,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC1G,mEAAmE;IACnE,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACtC;AAGD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgGlD,CAAC;AAEH,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ObjectsRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ObjectsRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACvH,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAU9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,oBAAoB,CAAC;AAE/D,UAAU,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,WAAW,CAAC;IAC5B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,qBAAqB,EAAE,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC1G,mEAAmE;IACnE,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACtC;AAGD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuGlD,CAAC;AAEH,eAAe,eAAe,CAAC"}
@@ -10,6 +10,8 @@ import { installStallLog } from '../utils/stallLog.js';
10
10
  import { findById } from '../utils/sceneQuery.js';
11
11
  import { commandsOf, sceneReadiness } from '../triggers/index.js';
12
12
  import { useObjectReady } from '../hooks/useObjectReady.js';
13
+ import { useThree } from "@react-three/fiber";
14
+ import { shownHits } from '../utils/shownInScene.js';
13
15
  const ObjectsRenderer = memo(({ cameraSettings, createdObjects, generalObjectSettings, onObjectsReady, onObjectReady, onObjectDispose, handleObjectClick, sequences = [], clips = [], actionSequences = [], }) => {
14
16
  const groupRef = useRef(null);
15
17
  const objectsTree = useMemo(() => buildObjectTree(createdObjects), [createdObjects]);
@@ -30,6 +32,13 @@ const ObjectsRenderer = memo(({ cameraSettings, createdObjects, generalObjectSet
30
32
  readyObjectsCount.current = Math.max(0, readyObjectsCount.current - 1);
31
33
  onObjectDispose && onObjectDispose(object, ref);
32
34
  }, [onObjectDispose]);
35
+ // Pointer events reach only what is shown: R3F (like three's Raycaster) ignores `visible`, so
36
+ // objects inside a disabled group would still take hover / click and block what is behind them.
37
+ const setEvents = useThree(s => s.setEvents);
38
+ useEffect(() => {
39
+ setEvents({ filter: (hits) => shownHits(hits) });
40
+ return () => setEvents({ filter: undefined });
41
+ }, [setEvents]);
33
42
  // The wrapper group itself is an Object3D the parent may want to transform.
34
43
  useObjectReady(groupRef, generalObjectSettings, onObjectReady, onObjectDispose);
35
44
  function filterInteractionsByEvent(interactions, mouseEvent) {
@@ -1,3 +1,3 @@
1
- export declare const dataCenterServer = "https://3drise.ai/api/data/";
1
+ export declare const dataCenterServer: string;
2
2
  export declare const SELF_MANAGED_MATERIAL: Set<string>;
3
3
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,aAqBhC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,gBAAgB,QAA4B,CAAC;AAE1D,eAAO,MAAM,qBAAqB,aAqBhC,CAAC"}
package/dist/constants.js CHANGED
@@ -1,9 +1,20 @@
1
- const LOCAL_DATA_CENTER_SERVER = 'http://localhost:3001/api/data/';
2
1
  const PRODUCTION_DATA_CENTER_SERVER = 'https://3drise.ai/api/data/';
3
- const isLocalHostRuntime = typeof window !== 'undefined' &&
4
- (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');
5
- // export const dataCenterServer = isLocalHostRuntime ? LOCAL_DATA_CENTER_SERVER : PRODUCTION_DATA_CENTER_SERVER;
6
- export const dataCenterServer = PRODUCTION_DATA_CENTER_SERVER;
2
+ // Local override that never touches git or the published package. In the browser console run:
3
+ // localStorage.setItem('dataCenterServer', 'http://localhost:3001/api/data/')
4
+ // (localStorage.removeItem('dataCenterServer') to go back to production), then reload.
5
+ function resolveDataCenterServer() {
6
+ try {
7
+ const override = typeof localStorage !== 'undefined' ? localStorage.getItem('dataCenterServer') : null;
8
+ if (override)
9
+ return override.endsWith('/') ? override : `${override}/`;
10
+ }
11
+ catch {
12
+ // localStorage can throw when storage is blocked; fall back to production.
13
+ }
14
+ return PRODUCTION_DATA_CENTER_SERVER;
15
+ }
16
+ export const dataCenterServer = resolveDataCenterServer();
17
+ console.log('Data Center Server:', dataCenterServer);
7
18
  export const SELF_MANAGED_MATERIAL = new Set([
8
19
  // The landscape owns its shader: splat arrays, height blending and the
9
20
  // heightmap displacement are the material. useMaterialApplication would
@@ -1 +1 @@
1
- {"version":3,"file":"motionTrail.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/motionTrail.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,mBAAmB,EAAsB,MAAM,UAAU,CAAC;AAOxE,+GAA+G;AAC/G,wBAAgB,UAAU,SAAiB;AA4I3C,qCAAqC;AACrC,eAAO,MAAM,MAAM,EAAE,mBAAmB,EA6BvC,CAAC"}
1
+ {"version":3,"file":"motionTrail.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/motionTrail.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,mBAAmB,EAAsB,MAAM,UAAU,CAAC;AAOxE,+GAA+G;AAC/G,wBAAgB,UAAU,SAAiB;AAgJ3C,qCAAqC;AACrC,eAAO,MAAM,MAAM,EAAE,mBAAmB,EA6BvC,CAAC"}
@@ -28,6 +28,7 @@ import { gsap } from 'gsap';
28
28
  import { Color, Group, Matrix4, Vector3 } from 'three';
29
29
  import { defineOperation } from '../types.js';
30
30
  import { hideUntilWarm, warmHelpers, warmMode } from './warmup.js';
31
+ import { shownInScene } from '../../utils/shownInScene.js';
31
32
  import { cameraPos, measure, newHistory, record } from './trailCore.js';
32
33
  import { afterimage, chromaticEcho, longExposure } from './trailGhosts.js';
33
34
  import { streaks } from './trailStreaks.js';
@@ -78,7 +79,13 @@ function build(KEY, styleName, style, target, p) {
78
79
  } // the object left the scene
79
80
  ctx.cam = cameraPos(camAt);
80
81
  record(ctx, clock());
81
- style.update(ctx);
82
+ // The trail lives at the scene root, outside the object's parents: it hides with the object
83
+ // (itself or a disabled group above it). History keeps recording so it resumes in place.
84
+ const shown = shownInScene(target);
85
+ if (group.visible !== shown)
86
+ group.visible = shown;
87
+ if (shown)
88
+ style.update(ctx);
82
89
  };
83
90
  return st;
84
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"UiAnchorUpdater.d.ts","sourceRoot":"","sources":["../../src/ui/UiAnchorUpdater.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAmB,OAAO,EAAE,KAAK,MAAM,EAAiB,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAoCzF,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,QAMzI;AAID,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA0C9G;AAID,MAAM,CAAC,OAAO,UAAU,eAAe,QAMtC"}
1
+ {"version":3,"file":"UiAnchorUpdater.d.ts","sourceRoot":"","sources":["../../src/ui/UiAnchorUpdater.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAmB,OAAO,EAAE,KAAK,MAAM,EAAiB,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAqCzF,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,QAMzI;AAID,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA0C9G;AAID,MAAM,CAAC,OAAO,UAAU,eAAe,QAMtC"}
@@ -13,6 +13,7 @@
13
13
  import { useFrame } from '@react-three/fiber';
14
14
  import { Box3, Raycaster, Vector3 } from 'three';
15
15
  import { findById, findByName } from '../utils/sceneQuery.js';
16
+ import { shownInScene } from '../utils/shownInScene.js';
16
17
  import { uiAnchors } from './uiAnchors.js';
17
18
  const BOX_EVERY = 8; // frames between bounding-box refreshes
18
19
  const OCCLUDE_EVERY = 6; // frames between occlusion raycasts
@@ -93,7 +94,7 @@ export function updateAnchors(camera, scene, width, height, frame) {
93
94
  const dist = dir.length();
94
95
  _ray.set(from, dir.normalize());
95
96
  _ray.far = Math.max(0, dist - 0.02);
96
- const hits = _ray.intersectObjects(scene.children, true).filter(h => h.object.isMesh && h.object.visible && !insideSubtree(h.object, target));
97
+ const hits = _ray.intersectObjects(scene.children, true).filter(h => h.object.isMesh && shownInScene(h.object) && !insideSubtree(h.object, target));
97
98
  entry.el.toggleAttribute('data-occluded', hits.length > 0);
98
99
  }
99
100
  else if (!entry.occlude) {
@@ -1 +1 @@
1
- {"version":3,"file":"cursorPicking.d.ts","sourceRoot":"","sources":["../../src/utils/cursorPicking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;CACpC;AAUD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,GAAG,gBAAgB,CA0BlN"}
1
+ {"version":3,"file":"cursorPicking.d.ts","sourceRoot":"","sources":["../../src/utils/cursorPicking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;CACpC;AAUD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,GAAG,gBAAgB,CA0BlN"}
@@ -1,9 +1,10 @@
1
1
  import * as THREE from 'three';
2
+ import { shownInScene } from './shownInScene.js';
2
3
  const tmpPlane = new THREE.Plane();
3
4
  const tmpNormal = new THREE.Vector3();
4
5
  const tmpHitPoint = new THREE.Vector3();
5
6
  function pickSceneHit(raycaster, scene) {
6
- const hits = raycaster.intersectObjects(scene.children, true);
7
+ const hits = raycaster.intersectObjects(scene.children, true).filter(h => shownInScene(h.object));
7
8
  return hits.find(h => h.object.userData.interactible === true) ?? hits[0] ?? null;
8
9
  }
9
10
  export function pickCursorWorldPos(mode, raycaster, scene, camera, pointer, planeDistance, out) {
@@ -0,0 +1,13 @@
1
+ import type { Intersection, Object3D } from 'three';
2
+ /**
3
+ * Whether an Object3D is really shown: it and every ancestor up to the scene are visible.
4
+ *
5
+ * Three draws nothing under a hidden parent, but its Raycaster (and R3F's pointer events)
6
+ * ignore `visible` — so without this, objects inside a disabled group still catch hover /
7
+ * click, block clicks on what is behind them and occlude UI anchors.
8
+ * Pick proxies hide through `material.visible`, not `visible`, so they are unaffected.
9
+ */
10
+ export declare function shownInScene(obj: Object3D | null | undefined): boolean;
11
+ /** Ray hits on objects that are really shown (see shownInScene). */
12
+ export declare const shownHits: <T extends Intersection>(hits: T[]) => T[];
13
+ //# sourceMappingURL=shownInScene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shownInScene.d.ts","sourceRoot":"","sources":["../../src/utils/shownInScene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGtE;AAED,oEAAoE;AACpE,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,YAAY,EAAE,MAAM,CAAC,EAAE,KAAG,CAAC,EAA8C,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Whether an Object3D is really shown: it and every ancestor up to the scene are visible.
3
+ *
4
+ * Three draws nothing under a hidden parent, but its Raycaster (and R3F's pointer events)
5
+ * ignore `visible` — so without this, objects inside a disabled group still catch hover /
6
+ * click, block clicks on what is behind them and occlude UI anchors.
7
+ * Pick proxies hide through `material.visible`, not `visible`, so they are unaffected.
8
+ */
9
+ export function shownInScene(obj) {
10
+ for (let o = obj; o; o = o.parent)
11
+ if (!o.visible)
12
+ return false;
13
+ return true;
14
+ }
15
+ /** Ray hits on objects that are really shown (see shownInScene). */
16
+ export const shownHits = (hits) => hits.filter(h => shownInScene(h.object));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3driseai/3drise-viewer",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",