@3driseai/3drise-core 1.0.25 → 1.0.27
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/data/effectsDefaults.d.ts.map +1 -1
- package/dist/data/effectsDefaults.js +3 -1
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +1 -0
- package/dist/data/lightShadowDefaults.d.ts +14 -0
- package/dist/data/lightShadowDefaults.d.ts.map +1 -0
- package/dist/data/lightShadowDefaults.js +92 -0
- package/dist/properties/registry.d.ts.map +1 -1
- package/dist/properties/registry.js +7 -1
- package/dist/properties/tables/effectsProperties.d.ts.map +1 -1
- package/dist/properties/tables/effectsProperties.js +1 -0
- package/dist/types/generativeEffects.d.ts +2 -0
- package/dist/types/generativeEffects.d.ts.map +1 -1
- package/dist/types/scene3d.d.ts +31 -2
- package/dist/types/scene3d.d.ts.map +1 -1
- package/dist/utils/animationTargets.d.ts +57 -0
- package/dist/utils/animationTargets.d.ts.map +1 -0
- package/dist/utils/animationTargets.js +356 -0
- package/dist/utils/cdnUrls.d.ts +5 -0
- package/dist/utils/cdnUrls.d.ts.map +1 -0
- package/dist/utils/cdnUrls.js +8 -0
- package/dist/utils/handleMaterialEffects.d.ts +3 -0
- package/dist/utils/handleMaterialEffects.d.ts.map +1 -1
- package/dist/utils/handleMaterialEffects.js +29 -0
- package/dist/utils/handleTransformEffects.d.ts +14 -0
- package/dist/utils/handleTransformEffects.d.ts.map +1 -1
- package/dist/utils/handleTransformEffects.js +57 -30
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/materialApplicationUtils.d.ts +5 -1
- package/dist/utils/materialApplicationUtils.d.ts.map +1 -1
- package/dist/utils/materialApplicationUtils.js +9 -2
- package/dist/utils/objectEffects.d.ts +13 -0
- package/dist/utils/objectEffects.d.ts.map +1 -1
- package/dist/utils/objectEffects.js +53 -0
- package/package.json +1 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Animation targets — Self / Each / Targets on groups and models
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// An Animation-tab row on a group or a model reaches (AnimationOptions.scope):
|
|
6
|
+
// self the object as one piece — the old path, `to` absolute (not handled here)
|
|
7
|
+
// each every part on its own: a group's leaf child objects (full depth, through
|
|
8
|
+
// nested groups), a model's meshes
|
|
9
|
+
// targets only the chosen ones (AnimationOptions.targets), each on its own:
|
|
10
|
+
// group → child objects by id (a model child optionally narrowed to nodes),
|
|
11
|
+
// model → nodes by name (every layout copy)
|
|
12
|
+
//
|
|
13
|
+
// Transform `to` on each / targets is RELATIVE to the target's own rest value:
|
|
14
|
+
// position / rotation are added, scale is multiplied. Material `to` stays absolute.
|
|
15
|
+
//
|
|
16
|
+
// Rest values:
|
|
17
|
+
// a scene object root (a group child) → `userData.baseTransform`, written by the
|
|
18
|
+
// viewer's AnimatedObject from the object's settings, so editing the child in the
|
|
19
|
+
// studio moves its rest too;
|
|
20
|
+
// a model node / mesh → snapshotted before the first write (it already carries any
|
|
21
|
+
// saved node override).
|
|
22
|
+
// A target the rows stop driving (row removed, switched off, scope changed) is put
|
|
23
|
+
// back on its rest at the end of the frame (`AnimationTargetState.endFrame`).
|
|
24
|
+
//
|
|
25
|
+
// Materials: a model node whose material is shared with a mesh outside the targets
|
|
26
|
+
// gets its own clone before the first write (otherwise the whole model changes);
|
|
27
|
+
// the original is put back when nothing drives that node's material any more.
|
|
28
|
+
//
|
|
29
|
+
// Stagger (AnimationOptions.stagger): each target starts `delay` seconds later, its
|
|
30
|
+
// delay = total · rank / (n − 1), rank by tree order / axis / centre-out / seeded random.
|
|
31
|
+
//
|
|
32
|
+
import { Box3, Vector3 } from 'three';
|
|
33
|
+
import { findNodesByName } from './nodeOverrides.js';
|
|
34
|
+
import { getMaterialPropertyValue, applyMaterialPropertyToObject } from './materialUtils.js';
|
|
35
|
+
/** What kind of root the scope works on; null = scope does not apply (self). */
|
|
36
|
+
export function targetRootKind(root) {
|
|
37
|
+
const t = root.userData?.objectType;
|
|
38
|
+
return t === 'group' || t === 'model' ? t : null;
|
|
39
|
+
}
|
|
40
|
+
/** The scope a row really runs with on this root ('self' when it cannot apply). */
|
|
41
|
+
export function effectiveScope(root, anim) {
|
|
42
|
+
const scope = anim.scope ?? 'self';
|
|
43
|
+
if (scope === 'self' || !targetRootKind(root))
|
|
44
|
+
return 'self';
|
|
45
|
+
if (scope === 'targets' && !anim.targets?.length)
|
|
46
|
+
return 'self';
|
|
47
|
+
return scope;
|
|
48
|
+
}
|
|
49
|
+
const isFxHelper = (o) => !!o.userData?.__opFxHelper;
|
|
50
|
+
/** Leaf object roots under a group (through nested groups), tree order. */
|
|
51
|
+
function groupLeaves(root) {
|
|
52
|
+
const out = [];
|
|
53
|
+
const walk = (n) => {
|
|
54
|
+
for (const c of n.children) {
|
|
55
|
+
if (isFxHelper(c))
|
|
56
|
+
continue;
|
|
57
|
+
if (c.userData?.id) {
|
|
58
|
+
if (c.userData.objectType === 'group')
|
|
59
|
+
walk(c);
|
|
60
|
+
else
|
|
61
|
+
out.push(c);
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
walk(c);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
walk(root);
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/** The object root with this id under `root` (any depth). */
|
|
71
|
+
function findObjectRoot(root, id) {
|
|
72
|
+
let hit = null;
|
|
73
|
+
root.traverse((c) => { if (!hit && c !== root && c.userData?.id === id)
|
|
74
|
+
hit = c; });
|
|
75
|
+
return hit;
|
|
76
|
+
}
|
|
77
|
+
/** A model's meshes, tree order (effect helpers left out). */
|
|
78
|
+
function meshesOf(root) {
|
|
79
|
+
const out = [];
|
|
80
|
+
const walk = (n) => {
|
|
81
|
+
for (const c of n.children) {
|
|
82
|
+
if (isFxHelper(c))
|
|
83
|
+
continue;
|
|
84
|
+
if (c.isMesh)
|
|
85
|
+
out.push(c);
|
|
86
|
+
walk(c);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
walk(root);
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
const nodesNamed = (root, name) => findNodesByName(root, name).filter(n => n !== root);
|
|
93
|
+
/**
|
|
94
|
+
* The Object3Ds a row reaches on `root`, in tree order, without duplicates.
|
|
95
|
+
* 'self' (or a root that is neither a group nor a model) → [root].
|
|
96
|
+
*/
|
|
97
|
+
export function resolveAnimationTargets(root, scope, targets) {
|
|
98
|
+
const kind = targetRootKind(root);
|
|
99
|
+
if (!kind || !scope || scope === 'self')
|
|
100
|
+
return [root];
|
|
101
|
+
let out;
|
|
102
|
+
if (kind === 'group') {
|
|
103
|
+
if (scope === 'each')
|
|
104
|
+
out = groupLeaves(root);
|
|
105
|
+
else {
|
|
106
|
+
out = [];
|
|
107
|
+
for (const t of targets ?? []) {
|
|
108
|
+
const child = findObjectRoot(root, t.id);
|
|
109
|
+
if (!child)
|
|
110
|
+
continue;
|
|
111
|
+
if (t.nodes?.length)
|
|
112
|
+
for (const n of t.nodes)
|
|
113
|
+
out.push(...nodesNamed(child, n));
|
|
114
|
+
else
|
|
115
|
+
out.push(child);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
if (scope === 'each')
|
|
121
|
+
out = meshesOf(root);
|
|
122
|
+
else {
|
|
123
|
+
out = [];
|
|
124
|
+
for (const t of targets ?? [])
|
|
125
|
+
out.push(...nodesNamed(root, t.id));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return [...new Set(out)];
|
|
129
|
+
}
|
|
130
|
+
// -----------------------------------------------------------------------------
|
|
131
|
+
// Stagger
|
|
132
|
+
// -----------------------------------------------------------------------------
|
|
133
|
+
const hash = (s) => { let h = 2166136261; for (let i = 0; i < s.length; i++) {
|
|
134
|
+
h ^= s.charCodeAt(i);
|
|
135
|
+
h = Math.imul(h, 16777619);
|
|
136
|
+
} return h >>> 0; };
|
|
137
|
+
function mulberry32(seed) {
|
|
138
|
+
return () => {
|
|
139
|
+
seed |= 0;
|
|
140
|
+
seed = (seed + 0x6d2b79f5) | 0;
|
|
141
|
+
let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
|
|
142
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
143
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Seconds each target waits, same order as `objs`. No stagger / total 0 / one target → all 0. */
|
|
147
|
+
export function staggerDelays(root, objs, stagger, seed) {
|
|
148
|
+
const n = objs.length;
|
|
149
|
+
const total = Math.max(0, Number(stagger?.total) || 0);
|
|
150
|
+
if (!total || n < 2)
|
|
151
|
+
return objs.map(() => 0);
|
|
152
|
+
const order = stagger?.order ?? 'tree';
|
|
153
|
+
let ranked; // indices into objs, first goes first
|
|
154
|
+
if (order === 'tree')
|
|
155
|
+
ranked = objs.map((_, i) => i);
|
|
156
|
+
else if (order === 'random') {
|
|
157
|
+
const rnd = mulberry32(hash(seed));
|
|
158
|
+
ranked = objs.map((_, i) => i);
|
|
159
|
+
for (let i = n - 1; i > 0; i--) {
|
|
160
|
+
const j = Math.floor(rnd() * (i + 1));
|
|
161
|
+
[ranked[i], ranked[j]] = [ranked[j], ranked[i]];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
root.updateWorldMatrix(true, true);
|
|
166
|
+
const box = new Box3();
|
|
167
|
+
const centres = objs.map((o) => {
|
|
168
|
+
const c = new Vector3();
|
|
169
|
+
box.setFromObject(o);
|
|
170
|
+
if (box.isEmpty())
|
|
171
|
+
o.getWorldPosition(c);
|
|
172
|
+
else
|
|
173
|
+
box.getCenter(c);
|
|
174
|
+
return root.worldToLocal(c);
|
|
175
|
+
});
|
|
176
|
+
let key;
|
|
177
|
+
if (order === 'radial') {
|
|
178
|
+
const mid = centres.reduce((a, c) => a.add(c), new Vector3()).divideScalar(n);
|
|
179
|
+
key = (c) => c.distanceTo(mid);
|
|
180
|
+
}
|
|
181
|
+
else
|
|
182
|
+
key = (c) => c[order];
|
|
183
|
+
ranked = objs.map((_, i) => i).sort((a, b) => key(centres[a]) - key(centres[b]) || a - b);
|
|
184
|
+
}
|
|
185
|
+
const delays = new Array(n).fill(0);
|
|
186
|
+
ranked.forEach((idx, rank) => { delays[idx] = (total * rank) / (n - 1); });
|
|
187
|
+
return delays;
|
|
188
|
+
}
|
|
189
|
+
/** Re-resolve a row's targets this often (frames) — children join / leave, models load. */
|
|
190
|
+
const RESOLVE_EVERY = 60;
|
|
191
|
+
export class AnimationTargetState {
|
|
192
|
+
root;
|
|
193
|
+
frame = 0;
|
|
194
|
+
resolved = new Map();
|
|
195
|
+
/** Transform rest snapshots of nodes (object roots use userData.baseTransform). */
|
|
196
|
+
restT = new Map();
|
|
197
|
+
/** Material rest values per target and property. */
|
|
198
|
+
restM = new Map();
|
|
199
|
+
/** Written this frame / last frame: `${uuid}|t|position` → target. */
|
|
200
|
+
touched = new Map();
|
|
201
|
+
last = new Map();
|
|
202
|
+
/** Material clones made per target node. */
|
|
203
|
+
owned = new Map();
|
|
204
|
+
constructor(root) {
|
|
205
|
+
this.root = root;
|
|
206
|
+
}
|
|
207
|
+
get object() { return this.root; }
|
|
208
|
+
beginFrame() {
|
|
209
|
+
this.frame++;
|
|
210
|
+
this.last = this.touched;
|
|
211
|
+
this.touched = new Map();
|
|
212
|
+
}
|
|
213
|
+
/** Targets + delays of a row, cached. */
|
|
214
|
+
targetsOf(anim, scope) {
|
|
215
|
+
const key = `${anim.property}|${scope}|${JSON.stringify(anim.targets ?? null)}|${JSON.stringify(anim.stagger ?? null)}`;
|
|
216
|
+
const hit = this.resolved.get(key);
|
|
217
|
+
if (hit && this.frame - hit.frame < RESOLVE_EVERY && hit.objs.every(o => o.parent))
|
|
218
|
+
return hit;
|
|
219
|
+
const objs = resolveAnimationTargets(this.root, scope, anim.targets);
|
|
220
|
+
const same = hit && hit.objs.length === objs.length && hit.objs.every((o, i) => o === objs[i]);
|
|
221
|
+
const delays = same ? hit.delays : staggerDelays(this.root, objs, anim.stagger, `${this.root.userData?.id ?? this.root.uuid}|${anim.property}`);
|
|
222
|
+
const next = { objs, delays, frame: this.frame };
|
|
223
|
+
this.resolved.set(key, next);
|
|
224
|
+
return next;
|
|
225
|
+
}
|
|
226
|
+
/** Keep a target on what it has (a hover row while not hovered): not restored this frame. */
|
|
227
|
+
hold(obj, domain, prop) {
|
|
228
|
+
const k = `${obj.uuid}|${domain}|${prop}`;
|
|
229
|
+
const prev = this.last.get(k);
|
|
230
|
+
if (prev)
|
|
231
|
+
this.touched.set(k, prev);
|
|
232
|
+
}
|
|
233
|
+
// ---- transform ----------------------------------------------------------
|
|
234
|
+
transformRest(obj, prop) {
|
|
235
|
+
const base = obj.userData?.baseTransform?.[prop];
|
|
236
|
+
if (Array.isArray(base) && base.length >= 3)
|
|
237
|
+
return [base[0], base[1], base[2]];
|
|
238
|
+
let snap = this.restT.get(obj);
|
|
239
|
+
if (!snap) {
|
|
240
|
+
snap = {};
|
|
241
|
+
this.restT.set(obj, snap);
|
|
242
|
+
}
|
|
243
|
+
if (!snap[prop]) {
|
|
244
|
+
const v = obj[prop];
|
|
245
|
+
snap[prop] = [v.x, v.y, v.z];
|
|
246
|
+
}
|
|
247
|
+
return snap[prop];
|
|
248
|
+
}
|
|
249
|
+
writeTransform(obj, prop, v) {
|
|
250
|
+
obj[prop].set(v[0], v[1], v[2]);
|
|
251
|
+
this.touched.set(`${obj.uuid}|t|${prop}`, { obj, domain: 't', prop });
|
|
252
|
+
}
|
|
253
|
+
/** Mark a transform as driven without writing (keyframe rows write themselves). */
|
|
254
|
+
touchTransform(obj, prop) {
|
|
255
|
+
this.transformRest(obj, prop);
|
|
256
|
+
this.touched.set(`${obj.uuid}|t|${prop}`, { obj, domain: 't', prop });
|
|
257
|
+
}
|
|
258
|
+
// ---- material -----------------------------------------------------------
|
|
259
|
+
/** The target's own value before the first write (what it goes back to). */
|
|
260
|
+
materialRest(obj, prop) {
|
|
261
|
+
let rec = this.restM.get(obj);
|
|
262
|
+
if (!rec) {
|
|
263
|
+
rec = {};
|
|
264
|
+
this.restM.set(obj, rec);
|
|
265
|
+
}
|
|
266
|
+
if (!(prop in rec))
|
|
267
|
+
rec[prop] = getMaterialPropertyValue(obj, prop);
|
|
268
|
+
return rec[prop];
|
|
269
|
+
}
|
|
270
|
+
writeMaterial(obj, prop, value) {
|
|
271
|
+
if (!obj.userData?.id)
|
|
272
|
+
this.ownMaterials(obj);
|
|
273
|
+
applyMaterialPropertyToObject(obj, prop, value);
|
|
274
|
+
this.touched.set(`${obj.uuid}|m|${prop}`, { obj, domain: 'm', prop });
|
|
275
|
+
}
|
|
276
|
+
/** A model node: clone the materials it shares with meshes outside it (once). */
|
|
277
|
+
ownMaterials(node) {
|
|
278
|
+
if (this.owned.has(node))
|
|
279
|
+
return;
|
|
280
|
+
const inside = new Set();
|
|
281
|
+
node.traverse(c => inside.add(c));
|
|
282
|
+
const sharedOutside = new Set();
|
|
283
|
+
this.root.traverse((c) => {
|
|
284
|
+
if (inside.has(c))
|
|
285
|
+
return;
|
|
286
|
+
const m = c.material;
|
|
287
|
+
if (!m)
|
|
288
|
+
return;
|
|
289
|
+
for (const x of Array.isArray(m) ? m : [m])
|
|
290
|
+
if (x)
|
|
291
|
+
sharedOutside.add(x);
|
|
292
|
+
});
|
|
293
|
+
const list = [];
|
|
294
|
+
node.traverse((c) => {
|
|
295
|
+
const m = c.material;
|
|
296
|
+
if (!m || isFxHelper(c))
|
|
297
|
+
return;
|
|
298
|
+
const arr = Array.isArray(m) ? m : [m];
|
|
299
|
+
if (!arr.some(x => sharedOutside.has(x)))
|
|
300
|
+
return;
|
|
301
|
+
list.push({ mesh: c, original: m });
|
|
302
|
+
c.material = Array.isArray(m) ? m.map(x => (sharedOutside.has(x) ? x.clone() : x)) : m.clone();
|
|
303
|
+
});
|
|
304
|
+
this.owned.set(node, list);
|
|
305
|
+
}
|
|
306
|
+
releaseMaterials(node) {
|
|
307
|
+
const list = this.owned.get(node);
|
|
308
|
+
if (!list)
|
|
309
|
+
return;
|
|
310
|
+
for (const { mesh, original } of list) {
|
|
311
|
+
const cur = mesh.material;
|
|
312
|
+
for (const x of Array.isArray(cur) ? cur : [cur]) {
|
|
313
|
+
if (x && !(Array.isArray(original) ? original.includes(x) : original === x))
|
|
314
|
+
x.dispose?.();
|
|
315
|
+
}
|
|
316
|
+
mesh.material = original;
|
|
317
|
+
}
|
|
318
|
+
this.owned.delete(node);
|
|
319
|
+
this.restM.delete(node);
|
|
320
|
+
}
|
|
321
|
+
// ---- end of frame -------------------------------------------------------
|
|
322
|
+
/** Put back on their rest the targets driven last frame and not this frame. */
|
|
323
|
+
endFrame() {
|
|
324
|
+
for (const [k, t] of this.last) {
|
|
325
|
+
if (this.touched.has(k))
|
|
326
|
+
continue;
|
|
327
|
+
if (t.domain === 't') {
|
|
328
|
+
const prop = t.prop;
|
|
329
|
+
const r = this.transformRest(t.obj, prop);
|
|
330
|
+
t.obj[prop].set(r[0], r[1], r[2]);
|
|
331
|
+
this.restT.get(t.obj) && delete this.restT.get(t.obj)[prop];
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
const rec = this.restM.get(t.obj);
|
|
335
|
+
if (rec && t.prop in rec)
|
|
336
|
+
applyMaterialPropertyToObject(t.obj, t.prop, rec[t.prop]);
|
|
337
|
+
if (rec)
|
|
338
|
+
delete rec[t.prop];
|
|
339
|
+
const stillDriven = [...this.touched.values()].some(x => x.obj === t.obj && x.domain === 'm');
|
|
340
|
+
if (!stillDriven)
|
|
341
|
+
this.releaseMaterials(t.obj);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
this.last = new Map();
|
|
345
|
+
}
|
|
346
|
+
/** Everything back on its rest (the object goes away / the hook stops). */
|
|
347
|
+
dispose() {
|
|
348
|
+
this.beginFrame();
|
|
349
|
+
this.endFrame();
|
|
350
|
+
for (const node of [...this.owned.keys()])
|
|
351
|
+
this.releaseMaterials(node);
|
|
352
|
+
this.resolved.clear();
|
|
353
|
+
this.restT.clear();
|
|
354
|
+
this.restM.clear();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const SPACES_ORIGIN_HOST = ".sfo3.digitaloceanspaces.com/";
|
|
2
|
+
export declare const SPACES_CDN_HOST = ".sfo3.cdn.digitaloceanspaces.com/";
|
|
3
|
+
/** Origin Spaces URL → CDN URL. Anything else (CDN, data:, blob:, relative, null) passes through. */
|
|
4
|
+
export declare const toCdn: <T extends string | null | undefined>(url: T) => T;
|
|
5
|
+
//# sourceMappingURL=cdnUrls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdnUrls.d.ts","sourceRoot":"","sources":["../../src/utils/cdnUrls.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,kCAAkC,CAAC;AAClE,eAAO,MAAM,eAAe,sCAAsC,CAAC;AAEnE,qGAAqG;AACrG,eAAO,MAAM,KAAK,GAAI,CAAC,SAAS,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,CAAC,KAAG,CACuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Asset URLs are stored with the Spaces origin host (generatePublicUrl in data-center).
|
|
2
|
+
// Anything that DISPLAYS or FETCHES an asset goes through the Spaces CDN instead. The DB keeps
|
|
3
|
+
// the origin URL so string matches (templatesUsingUrl, delete key extraction) are unaffected —
|
|
4
|
+
// so call toCdn only where a URL is shown or fetched, never on a value that gets saved back.
|
|
5
|
+
export const SPACES_ORIGIN_HOST = '.sfo3.digitaloceanspaces.com/';
|
|
6
|
+
export const SPACES_CDN_HOST = '.sfo3.cdn.digitaloceanspaces.com/';
|
|
7
|
+
/** Origin Spaces URL → CDN URL. Anything else (CDN, data:, blob:, relative, null) passes through. */
|
|
8
|
+
export const toCdn = (url) => (typeof url === 'string' ? url.replace(SPACES_ORIGIN_HOST, SPACES_CDN_HOST) : url);
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Object3D } from "three";
|
|
2
2
|
import { AnimationOptions, ColorEffectV2, EffectState, MaterialSettings } from "../types";
|
|
3
|
+
import { type AnimationTargetState } from "./animationTargets";
|
|
3
4
|
export interface MaterialAnimationContext {
|
|
4
5
|
object: Object3D;
|
|
5
6
|
materialSettings: MaterialSettings;
|
|
6
7
|
/** Cache of start values for animations (property -> value) */
|
|
7
8
|
startValuesCache: Record<string, any>;
|
|
9
|
+
/** Groups / models: rows scoped each / targets run through it (see animationTargets.ts). */
|
|
10
|
+
targets?: AnimationTargetState;
|
|
8
11
|
}
|
|
9
12
|
export declare const DEBUG_MATERIAL_EFFECTS = false;
|
|
10
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleMaterialEffects.d.ts","sourceRoot":"","sources":["../../src/utils/handleMaterialEffects.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1F,MAAM,WAAW,wBAAwB;IACrC,MAAM,EAAE,QAAQ,CAAC;IACjB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"handleMaterialEffects.d.ts","sourceRoot":"","sources":["../../src/utils/handleMaterialEffects.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1F,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,MAAM,WAAW,wBAAwB;IACrC,MAAM,EAAE,QAAQ,CAAC;IACjB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,4FAA4F;IAC5F,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAClC;AAMD,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAmC5C;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,wBAAwB,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CA6B/I;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,wBAAwB,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAgBnJ;AA0BD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE;IACnH,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B,EAAE,eAAe,GAAE,OAAe,GAAG,IAAI,CAcjD"}
|
|
@@ -10,6 +10,7 @@ import { calculateTimeProgress, getMaterialPropertyValue, interpolateValue, appl
|
|
|
10
10
|
import { applyEasing, gsapEasingMap } from "./animationsUtils.js";
|
|
11
11
|
import { createDefaultEffectState, } from "./utils.js";
|
|
12
12
|
import { applyAllColorEffects } from "./frameAnimations.js";
|
|
13
|
+
import { effectiveScope } from "./animationTargets.js";
|
|
13
14
|
// =============================================================================
|
|
14
15
|
// DEBUG
|
|
15
16
|
// =============================================================================
|
|
@@ -98,9 +99,37 @@ export function handleMaterialAnimations(ctx, animations, currentTime, hovered)
|
|
|
98
99
|
if (property === "position" || property === "rotation" || property === "scale") {
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
102
|
+
const scope = ctx.targets ? effectiveScope(ctx.object, animation) : 'self';
|
|
103
|
+
if (scope !== 'self') {
|
|
104
|
+
animateMaterialTargets(ctx.targets, animation, scope, currentTime, hovered);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
101
107
|
animateMaterialProperty(ctx, animation, currentTime, hovered);
|
|
102
108
|
});
|
|
103
109
|
}
|
|
110
|
+
/** A row scoped each / targets: each target from its own value to `to` (absolute), `delay` later each (stagger). */
|
|
111
|
+
function animateMaterialTargets(state, animation, scope, currentTime, hovered) {
|
|
112
|
+
const { property, to, duration, ease, loop = false, yoyo = false } = animation;
|
|
113
|
+
if (to === undefined)
|
|
114
|
+
return;
|
|
115
|
+
const { objs, delays } = state.targetsOf(animation, scope);
|
|
116
|
+
if (animation.triggerMode === "hover" && !hovered) {
|
|
117
|
+
for (const o of objs)
|
|
118
|
+
state.hold(o, 'm', property);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const easing = ease ? (gsapEasingMap[ease] || ease) : null;
|
|
122
|
+
objs.forEach((target, i) => {
|
|
123
|
+
const rest = state.materialRest(target, property);
|
|
124
|
+
const from = animation.from !== undefined ? animation.from : rest;
|
|
125
|
+
if (from === null || from === undefined)
|
|
126
|
+
return;
|
|
127
|
+
let t = calculateTimeProgress(currentTime - delays[i] * 1000, duration, yoyo, loop);
|
|
128
|
+
if (easing)
|
|
129
|
+
t = applyEasing(easing, t);
|
|
130
|
+
state.writeMaterial(target, property, interpolateValue(property, from, to, t));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
104
133
|
// =============================================================================
|
|
105
134
|
// HANDLE MATERIAL EFFECTS (COLOR EFFECTS)
|
|
106
135
|
// =============================================================================
|
|
@@ -2,10 +2,24 @@ import type { Object3D } from 'three';
|
|
|
2
2
|
import type { AnimationOptions, Vector3Array } from "../types/scene3d";
|
|
3
3
|
import type { TransformEffectV2 } from "../types/objectSettings";
|
|
4
4
|
import type { EffectState } from "../types/effects";
|
|
5
|
+
import { type AnimationTargetState } from "./animationTargets";
|
|
5
6
|
export interface TransformAnimationContext {
|
|
6
7
|
object: Object3D;
|
|
7
8
|
meshSettings: any;
|
|
8
9
|
pathIsActive: boolean;
|
|
10
|
+
/** Groups / models: rows scoped each / targets run through it (see animationTargets.ts). Absent = every row on the object itself. */
|
|
11
|
+
targets?: AnimationTargetState;
|
|
12
|
+
/**
|
|
13
|
+
* A timeline clip driving a row's `to` (by its index in the list): laid over the authored value
|
|
14
|
+
* while the clip runs — live, never written to the settings. Absent / undefined = the row's own.
|
|
15
|
+
*/
|
|
16
|
+
liveTo?: (index: number) => Vector3Array | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* A timeline clip has taken this property over (the object itself: target null; a group's /
|
|
19
|
+
* model's child: that child). The clip has full control while it is active: the row stops on
|
|
20
|
+
* that target — nothing is added, nothing is restored — and runs again once the clip ends.
|
|
21
|
+
*/
|
|
22
|
+
takenOver?: (target: Object3D | null, property: 'position' | 'rotation' | 'scale') => boolean;
|
|
9
23
|
}
|
|
10
24
|
export declare const DEBUG_TRANSFORM_EFFECTS = false;
|
|
11
25
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleTransformEffects.d.ts","sourceRoot":"","sources":["../../src/utils/handleTransformEffects.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAKtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,MAAM,WAAW,yBAAyB;IACtC,MAAM,EAAE,QAAQ,CAAC;IACjB,YAAY,EAAE,GAAG,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"handleTransformEffects.d.ts","sourceRoot":"","sources":["../../src/utils/handleTransformEffects.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAKtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,MAAM,WAAW,yBAAyB;IACtC,MAAM,EAAE,QAAQ,CAAC;IACjB,YAAY,EAAE,GAAG,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,qIAAqI;IACrI,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAC;IACrD;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,KAAK,OAAO,CAAC;CACjG;AAMD,eAAO,MAAM,uBAAuB,QAAQ,CAAC;AAS7C;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,IAAI,CAwBpO;AAID;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,yBAAyB,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CA2CrK;AAyCD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE;IACtJ,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAqBjC"}
|
|
@@ -10,6 +10,7 @@ import { applyEasing, gsapEasingMap } from "./animationsUtils.js";
|
|
|
10
10
|
import { applyTransformEffects } from "../utils/frameAnimations.js";
|
|
11
11
|
import { calculateTimeProgress } from "./materialUtils.js";
|
|
12
12
|
import { createDefaultEffectState } from "./utils.js";
|
|
13
|
+
import { effectiveScope } from "./animationTargets.js";
|
|
13
14
|
// =============================================================================
|
|
14
15
|
// DEBUG
|
|
15
16
|
// =============================================================================
|
|
@@ -64,20 +65,27 @@ export function handleTransformAnimations(ctx, animations, currentTime, hovered,
|
|
|
64
65
|
// Without a delta (older callers) one frame, the old per-frame behaviour.
|
|
65
66
|
const frames = delta === undefined ? 1 : Math.min(Math.max(delta, 0), 0.1) * 60;
|
|
66
67
|
// console.log("handleTransformAnimations called with animations:", animations);
|
|
67
|
-
animations.forEach((
|
|
68
|
-
const
|
|
68
|
+
animations.forEach((row, index) => {
|
|
69
|
+
const live = ctx.liveTo?.(index);
|
|
70
|
+
const animation = live ? { ...row, to: live } : row;
|
|
71
|
+
const { property, ease, duration, loop = false, to, yoyo = false, active, type = "interpolation", triggerMode = "always", } = animation;
|
|
69
72
|
if (!active)
|
|
70
73
|
return;
|
|
71
|
-
|
|
74
|
+
// Only handle transform properties
|
|
75
|
+
if (property !== "position" && property !== "rotation" && property !== "scale") {
|
|
72
76
|
return;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
(
|
|
77
|
+
}
|
|
78
|
+
const scope = ctx.targets ? effectiveScope(object, animation) : 'self';
|
|
79
|
+
if (scope !== 'self') {
|
|
80
|
+
animateTargets(ctx.targets, animation, property, scope, currentTime, hovered, frames, ctx.takenOver);
|
|
77
81
|
return;
|
|
78
82
|
}
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
if (ctx.takenOver?.(null, property))
|
|
84
|
+
return; // a clip drives it: the clip has full control
|
|
85
|
+
if (triggerMode === "hover" && !hovered)
|
|
86
|
+
return;
|
|
87
|
+
// Skip position/rotation if path animation is active (path controls these)
|
|
88
|
+
if (pathIsActive && (property === "position" || property === "rotation")) {
|
|
81
89
|
return;
|
|
82
90
|
}
|
|
83
91
|
// Calculate animation progress
|
|
@@ -88,32 +96,51 @@ export function handleTransformAnimations(ctx, animations, currentTime, hovered,
|
|
|
88
96
|
timeProgress = applyEasing(easingFunctionName, timeProgress);
|
|
89
97
|
}
|
|
90
98
|
const animationSpeed = 1000 / duration;
|
|
91
|
-
// Determine which objects to animate
|
|
92
|
-
const targetsToAnimate = [];
|
|
93
|
-
if (objectIds && objectIds.length > 0) {
|
|
94
|
-
// Animate specific children by name
|
|
95
|
-
// Every match, not getObjectByName's first: a model repeated by
|
|
96
|
-
// meshSettings.layout has the same part name once per copy.
|
|
97
|
-
const names = new Set(objectIds);
|
|
98
|
-
object.traverse((child) => {
|
|
99
|
-
if (child.name && names.has(child.name)) {
|
|
100
|
-
targetsToAnimate.push(child);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
log("animating specific targets", { objectIds, found: targetsToAnimate.length });
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// Animate the parent object
|
|
107
|
-
targetsToAnimate.push(object);
|
|
108
|
-
}
|
|
109
99
|
// Get start value from meshSettings
|
|
110
100
|
const start = meshSettings[property];
|
|
111
101
|
if (!start || !to)
|
|
112
102
|
return;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
103
|
+
animateTransformProperty(object, property, start, to, timeProgress, type, animationSpeed, frames);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A row scoped each / targets: every target on its own, `to` relative to the target's rest
|
|
108
|
+
* (position / rotation added, scale multiplied), each target `delay` later (stagger).
|
|
109
|
+
*/
|
|
110
|
+
function animateTargets(state, animation, property, scope, currentTime, hovered, frames, takenOver) {
|
|
111
|
+
const { ease, duration, loop = false, to, yoyo = false, type = "interpolation", triggerMode = "always" } = animation;
|
|
112
|
+
const { objs, delays } = state.targetsOf(animation, scope);
|
|
113
|
+
if (triggerMode === "hover" && !hovered) {
|
|
114
|
+
for (const o of objs)
|
|
115
|
+
state.hold(o, 't', property);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (!Array.isArray(to) || to.length < 3)
|
|
119
|
+
return;
|
|
120
|
+
const isScale = property === "scale";
|
|
121
|
+
const animationSpeed = 1000 / duration;
|
|
122
|
+
const easing = ease ? (gsapEasingMap[ease] || ease) : null;
|
|
123
|
+
objs.forEach((target, i) => {
|
|
124
|
+
// a clip drives this target: leave it to the clip (held — not put back to its rest either)
|
|
125
|
+
if (takenOver?.(target, property)) {
|
|
126
|
+
state.hold(target, 't', property);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (type === "keyframe") {
|
|
130
|
+
// Continuous: the same increment per frame on each target (a stagger has nothing to offset).
|
|
131
|
+
state.touchTransform(target, property);
|
|
132
|
+
animateTransformProperty(target, property, [0, 0, 0], to, 0, "keyframe", animationSpeed, frames);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
let t = calculateTimeProgress(currentTime - delays[i] * 1000, duration, yoyo, loop);
|
|
136
|
+
if (easing)
|
|
137
|
+
t = applyEasing(easing, t);
|
|
138
|
+
const rest = state.transformRest(target, property);
|
|
139
|
+
const v = rest.map((r, k) => {
|
|
140
|
+
const d = Number(to[k]) || 0;
|
|
141
|
+
return isScale ? r * MathUtils.lerp(1, d, t) : r + MathUtils.lerp(0, d, t);
|
|
116
142
|
});
|
|
143
|
+
state.writeTransform(target, property, v);
|
|
117
144
|
});
|
|
118
145
|
}
|
|
119
146
|
// =============================================================================
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from './utils';
|
|
|
21
21
|
export * from './edgeUtils';
|
|
22
22
|
export * from './surfaceUtils';
|
|
23
23
|
export * from './objectTreeUtils';
|
|
24
|
+
export * from './animationTargets';
|
|
24
25
|
export * from './handleTransformEffects';
|
|
25
26
|
export * from './handleEdgesAnimations';
|
|
26
27
|
export * from './handleLightAnimations';
|
|
@@ -47,4 +48,5 @@ export * from './actionKeys';
|
|
|
47
48
|
export * from './objectEffects';
|
|
48
49
|
export * from './cameraControls';
|
|
49
50
|
export * from './materialVariant';
|
|
51
|
+
export * from './cdnUrls';
|
|
50
52
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -21,6 +21,7 @@ export * from './utils.js';
|
|
|
21
21
|
export * from './edgeUtils.js';
|
|
22
22
|
export * from './surfaceUtils.js';
|
|
23
23
|
export * from './objectTreeUtils.js';
|
|
24
|
+
export * from './animationTargets.js';
|
|
24
25
|
export * from './handleTransformEffects.js';
|
|
25
26
|
export * from './handleEdgesAnimations.js';
|
|
26
27
|
export * from './handleLightAnimations.js';
|
|
@@ -47,3 +48,4 @@ export * from './actionKeys.js';
|
|
|
47
48
|
export * from './objectEffects.js';
|
|
48
49
|
export * from './cameraControls.js';
|
|
49
50
|
export * from './materialVariant.js';
|
|
51
|
+
export * from './cdnUrls.js';
|
|
@@ -17,8 +17,12 @@ export declare const SELF_OWNED_MATERIAL_KEY = "__ownsItsMaterial";
|
|
|
17
17
|
* with EDGES_GROUP_KEY, GEREATIVE_EFFECTS_KEY or SELF_OWNED_MATERIAL_KEY — unless obj itself
|
|
18
18
|
* carries that mark (so an edges group or generative effects group can still
|
|
19
19
|
* apply its own material via useMaterialApplication).
|
|
20
|
+
* `stopAtObjects`: also stop at the roots of child scene objects — an object's material
|
|
21
|
+
* never reaches the objects parented under it (they apply their own).
|
|
20
22
|
*/
|
|
21
|
-
export declare function traverseSkippingEdgesAndEffects(obj: Object3D, isRoot: boolean, callback: (node: Object3D) => void): void;
|
|
23
|
+
export declare function traverseSkippingEdgesAndEffects(obj: Object3D, isRoot: boolean, callback: (node: Object3D) => void, stopAtObjects?: boolean): void;
|
|
24
|
+
/** The root of a scene object (the viewer's AnimatedObject tags it with its id and type). */
|
|
25
|
+
export declare const isSceneObjectRoot: (obj: Object3D) => boolean;
|
|
22
26
|
/**
|
|
23
27
|
* Create a fresh material instance for a variant and apply settings to it.
|
|
24
28
|
*/
|