@3driseai/3drise-viewer 0.1.39 → 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.
- package/dist/animationsV2/ClipsRuntime.d.ts +30 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +177 -10
- package/dist/animationsV2/clipUtils.d.ts +6 -0
- package/dist/animationsV2/clipUtils.d.ts.map +1 -1
- package/dist/animationsV2/clipUtils.js +28 -0
- package/dist/animationsV2/normalize.d.ts.map +1 -1
- package/dist/animationsV2/normalize.js +2 -0
- package/dist/animationsV2/types.d.ts +8 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- package/dist/components/AnimatedObject.d.ts.map +1 -1
- package/dist/components/AnimatedObject.js +6 -2
- package/dist/components/EnabledContext.d.ts +12 -0
- package/dist/components/EnabledContext.d.ts.map +1 -0
- package/dist/components/EnabledContext.js +12 -0
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +6 -1
- package/dist/components/ObjectsRenderer.d.ts.map +1 -1
- package/dist/components/ObjectsRenderer.js +9 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +16 -5
- package/dist/operations/catalogue/motionTrail.d.ts.map +1 -1
- package/dist/operations/catalogue/motionTrail.js +8 -1
- package/dist/ui/UiAnchorUpdater.d.ts.map +1 -1
- package/dist/ui/UiAnchorUpdater.js +2 -1
- package/dist/utils/cursorPicking.d.ts.map +1 -1
- package/dist/utils/cursorPicking.js +2 -1
- package/dist/utils/shownInScene.d.ts +13 -0
- package/dist/utils/shownInScene.d.ts.map +1 -0
- package/dist/utils/shownInScene.js +16 -0
- 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":"AA2CA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
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.
|
|
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
|
-
|
|
614
|
-
|
|
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 (
|
|
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
|
|
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,
|
|
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,6 +13,7 @@ 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')
|
|
@@ -56,6 +57,7 @@ export function normalizeSequence(row) {
|
|
|
56
57
|
yoyo: flag(row.yoyo),
|
|
57
58
|
reverse: flag(row.reverse),
|
|
58
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)) } : {}),
|
|
59
61
|
driver: DRIVERS.includes(row.driver) ? row.driver : 'time',
|
|
60
62
|
driverSettings: {
|
|
61
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;
|
|
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":"
|
|
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
|
-
|
|
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,
|
|
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) {
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
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":"
|
|
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
|
-
|
|
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;
|
|
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
|
|
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;
|
|
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));
|