@unseenco/theatre-core 0.4.1 → 0.4.3

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/index.d.ts CHANGED
@@ -1705,6 +1705,13 @@ declare function setCoreRafDriver(driver: IRafDriver): void;
1705
1705
  */
1706
1706
  declare function isRemoteEditorWindow(): boolean;
1707
1707
 
1708
+ /**
1709
+ * Drives registered GSAP animations from the sheet sequence playhead.
1710
+ *
1711
+ * @returns Disposer — call to detach the bridge.
1712
+ */
1713
+ declare function attachGsapSequenceBridge(sheet: ISheet): () => void;
1714
+
1708
1715
  /**
1709
1716
  * Returns a project of the given id, or creates one if it doesn't already exist.
1710
1717
  *
@@ -1790,4 +1797,4 @@ declare function val<T>(pointer: PointerType<T>): T;
1790
1797
  */
1791
1798
  type __UNSTABLE_Project_OnDiskState = OnDiskState;
1792
1799
 
1793
- export { IProject, IProjectConfig, IRafDriver, ISequence, ISheet, ISheetObject, ISheetObjectOptions, ISheetOptions, UnknownShorthandCompoundProps, __UNSTABLE_Project_OnDiskState, createRafDriver, getProject, isRemoteEditorWindow, notify, onChange, setCoreRafDriver, index_d as types, val };
1800
+ export { IProject, IProjectConfig, IRafDriver, ISequence, ISheet, ISheetObject, ISheetObjectOptions, ISheetOptions, UnknownShorthandCompoundProps, __UNSTABLE_Project_OnDiskState, attachGsapSequenceBridge, createRafDriver, getProject, isRemoteEditorWindow, notify, onChange, setCoreRafDriver, index_d as types, val };
package/dist/index.js CHANGED
@@ -241,28 +241,34 @@ var require_propose = __commonJS({
241
241
  // core/src/index.ts
242
242
  var index_exports = {};
243
243
  __export(index_exports, {
244
+ attachGsapSequenceBridge: () => attachGsapSequenceBridge,
244
245
  createRafDriver: () => createRafDriver,
245
246
  getProject: () => getProject,
246
247
  isRemoteEditorWindow: () => isRemoteEditorWindow,
247
248
  notify: () => notify,
248
249
  onChange: () => onChange,
250
+ privateAPI: () => privateAPI,
249
251
  setCoreRafDriver: () => setCoreRafDriver,
252
+ setPrivateAPI: () => setPrivateAPI,
250
253
  types: () => propTypes_exports,
251
- val: () => val10
254
+ val: () => val11
252
255
  });
253
256
  module.exports = __toCommonJS(index_exports);
254
257
 
255
258
  // core/src/coreExports.ts
256
259
  var coreExports_exports = {};
257
260
  __export(coreExports_exports, {
261
+ attachGsapSequenceBridge: () => attachGsapSequenceBridge,
258
262
  createRafDriver: () => createRafDriver,
259
263
  getProject: () => getProject,
260
264
  isRemoteEditorWindow: () => isRemoteEditorWindow,
261
265
  notify: () => notify,
262
266
  onChange: () => onChange,
267
+ privateAPI: () => privateAPI,
263
268
  setCoreRafDriver: () => setCoreRafDriver,
269
+ setPrivateAPI: () => setPrivateAPI,
264
270
  types: () => propTypes_exports,
265
- val: () => val10
271
+ val: () => val11
266
272
  });
267
273
 
268
274
  // core/src/projects/projectsSingleton.ts
@@ -3230,11 +3236,11 @@ function sanitizeCompoundProps(props) {
3230
3236
  );
3231
3237
  }
3232
3238
  }
3233
- const val11 = props[key];
3234
- if (isLonghandPropType(val11)) {
3235
- sanitizedProps[key] = val11;
3239
+ const val12 = props[key];
3240
+ if (isLonghandPropType(val12)) {
3241
+ sanitizedProps[key] = val12;
3236
3242
  } else {
3237
- sanitizedProps[key] = toLonghandProp(val11);
3243
+ sanitizedProps[key] = toLonghandProp(val12);
3238
3244
  }
3239
3245
  }
3240
3246
  return sanitizedProps;
@@ -3332,15 +3338,15 @@ var file = (defaultValue, opts = {}) => {
3332
3338
  deserializeAndSanitize: _ensureFile
3333
3339
  };
3334
3340
  };
3335
- var _ensureFile = (val11) => {
3336
- if (!val11) return void 0;
3341
+ var _ensureFile = (val12) => {
3342
+ if (!val12) return void 0;
3337
3343
  let valid = true;
3338
- if (typeof val11.id !== "string" && ![null, void 0].includes(val11.id)) {
3344
+ if (typeof val12.id !== "string" && ![null, void 0].includes(val12.id)) {
3339
3345
  valid = false;
3340
3346
  }
3341
- if (val11.type !== "file") valid = false;
3347
+ if (val12.type !== "file") valid = false;
3342
3348
  if (!valid) return void 0;
3343
- return val11;
3349
+ return val12;
3344
3350
  };
3345
3351
  var image = (defaultValue, opts = {}) => {
3346
3352
  if (process.env.NODE_ENV !== "production") {
@@ -3364,15 +3370,15 @@ var image = (defaultValue, opts = {}) => {
3364
3370
  deserializeAndSanitize: _ensureImage
3365
3371
  };
3366
3372
  };
3367
- var _ensureImage = (val11) => {
3368
- if (!val11) return void 0;
3373
+ var _ensureImage = (val12) => {
3374
+ if (!val12) return void 0;
3369
3375
  let valid = true;
3370
- if (typeof val11.id !== "string" && ![null, void 0].includes(val11.id)) {
3376
+ if (typeof val12.id !== "string" && ![null, void 0].includes(val12.id)) {
3371
3377
  valid = false;
3372
3378
  }
3373
- if (val11.type !== "image") valid = false;
3379
+ if (val12.type !== "image") valid = false;
3374
3380
  if (!valid) return void 0;
3375
- return val11;
3381
+ return val12;
3376
3382
  };
3377
3383
  var number = (defaultValue, opts = {}) => {
3378
3384
  if (process.env.NODE_ENV !== "production") {
@@ -3495,11 +3501,11 @@ var rgba = (defaultValue = { r: 0, g: 0, b: 0, a: 1 }, opts = {}) => {
3495
3501
  deserializeAndSanitize: _sanitizeRgba
3496
3502
  };
3497
3503
  };
3498
- var _sanitizeRgba = (val11) => {
3499
- if (!val11) return void 0;
3504
+ var _sanitizeRgba = (val12) => {
3505
+ if (!val12) return void 0;
3500
3506
  let valid = true;
3501
3507
  for (const c2 of ["r", "g", "b", "a"]) {
3502
- if (!Object.prototype.hasOwnProperty.call(val11, c2) || typeof val11[c2] !== "number") {
3508
+ if (!Object.prototype.hasOwnProperty.call(val12, c2) || typeof val12[c2] !== "number") {
3503
3509
  valid = false;
3504
3510
  }
3505
3511
  }
@@ -3508,7 +3514,7 @@ var _sanitizeRgba = (val11) => {
3508
3514
  for (const c2 of ["r", "g", "b", "a"]) {
3509
3515
  ;
3510
3516
  sanitized[c2] = Math.min(
3511
- Math.max(val11[c2], 0),
3517
+ Math.max(val12[c2], 0),
3512
3518
  1
3513
3519
  );
3514
3520
  }
@@ -3547,8 +3553,8 @@ var boolean = (defaultValue, opts = {}) => {
3547
3553
  deserializeAndSanitize: _ensureBoolean
3548
3554
  };
3549
3555
  };
3550
- var _ensureBoolean = (val11) => {
3551
- return typeof val11 === "boolean" ? val11 : void 0;
3556
+ var _ensureBoolean = (val12) => {
3557
+ return typeof val12 === "boolean" ? val12 : void 0;
3552
3558
  };
3553
3559
  function leftInterpolate(left) {
3554
3560
  return left;
@@ -3755,8 +3761,8 @@ var TheatreSheetObject = class {
3755
3761
  }
3756
3762
  return der.getValue();
3757
3763
  }
3758
- set initialValue(val11) {
3759
- privateAPI(this).setInitialValue(val11);
3764
+ set initialValue(val12) {
3765
+ privateAPI(this).setInitialValue(val12);
3760
3766
  }
3761
3767
  showPropsOf(objects) {
3762
3768
  const host = privateAPI(this);
@@ -4524,9 +4530,9 @@ var SheetObject = class {
4524
4530
  }
4525
4531
  validateValue(pointer3, value) {
4526
4532
  }
4527
- setInitialValue(val11) {
4528
- this.validateValue(this.propsP, val11);
4529
- this._initialValue.set(val11);
4533
+ setInitialValue(val12) {
4534
+ this.validateValue(this.propsP, val12);
4535
+ this._initialValue.set(val12);
4530
4536
  }
4531
4537
  setSessionOverride(path, value) {
4532
4538
  const propConfig = getPropConfigByPath(this.template.staticConfig, path);
@@ -4546,8 +4552,8 @@ var SheetObject = class {
4546
4552
  * Internal: called by `RemoteSync` when a value update for this object
4547
4553
  * arrives from a remote editor window. Not exposed on the public API.
4548
4554
  */
4549
- setRemoteOverride(val11) {
4550
- this._remoteOverride.set(val11);
4555
+ setRemoteOverride(val12) {
4556
+ this._remoteOverride.set(val12);
4551
4557
  }
4552
4558
  /**
4553
4559
  * Internal: used by `RemoteSync` to subscribe to this object's fully
@@ -6219,6 +6225,19 @@ function isBasicKeyframedTrack(track) {
6219
6225
  function isGsapClipTrack(track) {
6220
6226
  return track.type === "GsapClipTrack";
6221
6227
  }
6228
+ function gsapClipEndTime(clip) {
6229
+ return clip.start + clip.duration;
6230
+ }
6231
+ function gsapClipSyncProgress(sequencePosition, clip) {
6232
+ if (clip.duration <= 0) return 0;
6233
+ if (sequencePosition < clip.start) return 0;
6234
+ const clipEnd = gsapClipEndTime(clip);
6235
+ if (sequencePosition >= clipEnd - 1e-5) return 1;
6236
+ const raw = (sequencePosition - clip.start) / clip.duration;
6237
+ if (raw <= 0) return 0;
6238
+ if (raw >= 1) return 1;
6239
+ return raw;
6240
+ }
6222
6241
 
6223
6242
  // core/src/sequences/Sequence.ts
6224
6243
  var possibleDirections = [
@@ -8347,13 +8366,13 @@ var Project = class {
8347
8366
  };
8348
8367
 
8349
8368
  // shared/src/utils/sanitizers.ts
8350
- var _validateSym = (val11, thingy, range) => {
8351
- if (typeof val11 !== "string") {
8352
- return "".concat(thingy, " must be a string. ").concat(userReadableTypeOfValue_default(val11), " given.");
8353
- } else if (val11.trim().length !== val11.length) {
8354
- return "".concat(thingy, " must not have leading or trailing spaces. '").concat(val11, "' given.");
8355
- } else if (val11.length < range[0] || val11.length > range[1]) {
8356
- return "".concat(thingy, " must have between ").concat(range[0], " and ").concat(range[1], " characters. '").concat(val11, "' given.");
8369
+ var _validateSym = (val12, thingy, range) => {
8370
+ if (typeof val12 !== "string") {
8371
+ return "".concat(thingy, " must be a string. ").concat(userReadableTypeOfValue_default(val12), " given.");
8372
+ } else if (val12.trim().length !== val12.length) {
8373
+ return "".concat(thingy, " must not have leading or trailing spaces. '").concat(val12, "' given.");
8374
+ } else if (val12.length < range[0] || val12.length > range[1]) {
8375
+ return "".concat(thingy, " must have between ").concat(range[0], " and ").concat(range[1], " characters. '").concat(val12, "' given.");
8357
8376
  }
8358
8377
  };
8359
8378
  var validateName = (name, thingy, shouldThrow = false) => {
@@ -8469,8 +8488,194 @@ var TheatreProject = class {
8469
8488
 
8470
8489
  // core/src/coreExports.ts
8471
8490
  var import_fast_deep_equal3 = __toESM(require_fast_deep_equal());
8491
+ var import_theatre_dataverse23 = require("@unseenco/theatre-dataverse");
8492
+ var import_theatre_dataverse24 = require("@unseenco/theatre-dataverse");
8493
+
8494
+ // shared/src/gsap/applyTimelineChildTiming.ts
8495
+ function applyTimelineChildTimingToGsap(rootAnimation, timelineChildren, childById, onRebuild) {
8496
+ if (!timelineChildren.length) return true;
8497
+ let ok = applyTimelineChildTimingToGsapInner(
8498
+ rootAnimation,
8499
+ timelineChildren,
8500
+ childById
8501
+ );
8502
+ if (!ok && onRebuild) {
8503
+ const rebuilt = onRebuild();
8504
+ if (rebuilt) {
8505
+ ok = applyTimelineChildTimingToGsapInner(
8506
+ rebuilt,
8507
+ timelineChildren,
8508
+ childById
8509
+ );
8510
+ }
8511
+ }
8512
+ return ok;
8513
+ }
8514
+ function applyTimelineChildTimingToGsapInner(rootAnimation, timelineChildren, childById) {
8515
+ if (!childById || timelineChildren.length === 0) return true;
8516
+ let ok = true;
8517
+ for (const childState of timelineChildren) {
8518
+ const tween = childById.get(childState.childId);
8519
+ if (!tween) continue;
8520
+ try {
8521
+ const t2 = tween;
8522
+ if (typeof t2.startTime === "function") {
8523
+ t2.startTime(childState.localStart);
8524
+ }
8525
+ if (typeof t2.duration === "function") {
8526
+ t2.duration(childState.localDuration);
8527
+ }
8528
+ } catch {
8529
+ ok = false;
8530
+ }
8531
+ }
8532
+ return ok;
8533
+ }
8534
+
8535
+ // shared/src/gsap/syncGsapClipProgress.ts
8536
+ function getGsapAnimationTargetKey(animation, fallbackAnimationId) {
8537
+ const tween = animation;
8538
+ const targets = tween.targets?.();
8539
+ if (targets && targets.length > 0) {
8540
+ return targets[0];
8541
+ }
8542
+ return fallbackAnimationId;
8543
+ }
8544
+ function syncRegisteredGsapAnimationsForClips(sequencePosition, clips) {
8545
+ const enriched = [];
8546
+ for (const clip of clips) {
8547
+ const entry = getAnimationEntryBySheetAddressKey(
8548
+ clip.sheetObjectAddressKey,
8549
+ clip.gsapAnimationId
8550
+ );
8551
+ if (!entry?.animation) continue;
8552
+ enriched.push({
8553
+ ...clip,
8554
+ entry,
8555
+ targetKey: getGsapAnimationTargetKey(
8556
+ entry.animation,
8557
+ clip.gsapAnimationId
8558
+ )
8559
+ });
8560
+ }
8561
+ const byTarget = /* @__PURE__ */ new Map();
8562
+ for (const item of enriched) {
8563
+ const list = byTarget.get(item.targetKey) ?? [];
8564
+ list.push(item);
8565
+ byTarget.set(item.targetKey, list);
8566
+ }
8567
+ for (const group of byTarget.values()) {
8568
+ const sorted = [...group].sort((a2, b2) => a2.start - b2.start);
8569
+ for (const clip of sorted) {
8570
+ const progress = gsapClipSyncProgress(sequencePosition, clip);
8571
+ const entry = clip.entry;
8572
+ const animation = entry.animation;
8573
+ if (entry.kind === "timeline" && clip.timelineChildren && clip.timelineChildren.length > 0) {
8574
+ applyTimelineChildTimingToGsap(
8575
+ entry.animation,
8576
+ clip.timelineChildren,
8577
+ entry.timelineChildById,
8578
+ entry.onRebuildTimeline
8579
+ );
8580
+ const span = clip.timelineSpan ?? readGsapTweenTimelineDuration(entry.animation);
8581
+ const t2 = progress * Math.max(span, 0.01);
8582
+ if (typeof animation.time === "function") {
8583
+ animation.time(t2, true);
8584
+ } else {
8585
+ animation.progress?.(progress, true);
8586
+ }
8587
+ } else {
8588
+ animation.progress?.(progress, true);
8589
+ }
8590
+ }
8591
+ }
8592
+ }
8593
+ function readGsapTweenTimelineDuration(animation) {
8594
+ const tween = animation;
8595
+ const total = tween.totalDuration?.();
8596
+ if (typeof total === "number" && total > 0) return total;
8597
+ const d2 = tween.duration();
8598
+ return d2 > 0 ? d2 : 1;
8599
+ }
8600
+
8601
+ // shared/src/gsap/gsapStudioRegistryRevision.ts
8472
8602
  var import_theatre_dataverse21 = require("@unseenco/theatre-dataverse");
8603
+ var revisionAtom = new import_theatre_dataverse21.Atom(0);
8604
+ var gsapStudioRegistryRevisionPointer = revisionAtom.pointer;
8605
+
8606
+ // shared/src/gsap/gsapAnimationRegistry.ts
8607
+ var DEFAULT_SHEET_INSTANCE_ID = "default";
8608
+ var REGISTRY_KEY = "__unseenco_theatre_gsap_animationRegistry__";
8609
+ function sheetObjectAddressKeyFromParts(address) {
8610
+ const sheetInstanceId = address.sheetInstanceId ?? DEFAULT_SHEET_INSTANCE_ID;
8611
+ return "".concat(address.projectId, "|").concat(address.sheetId, "|").concat(sheetInstanceId, "|").concat(address.objectKey);
8612
+ }
8613
+ function getStore() {
8614
+ const g2 = globalThis;
8615
+ if (!g2[REGISTRY_KEY]) {
8616
+ g2[REGISTRY_KEY] = {
8617
+ bySheetAddress: /* @__PURE__ */ new Map()
8618
+ };
8619
+ }
8620
+ return g2[REGISTRY_KEY];
8621
+ }
8622
+ function getAnimationEntryBySheetAddressKey(sheetObjectAddressKey, animationId) {
8623
+ return getStore().bySheetAddress.get(sheetObjectAddressKey)?.get(animationId);
8624
+ }
8625
+
8626
+ // shared/src/gsap/subscribeGsapClipSyncAtPlayhead.ts
8473
8627
  var import_theatre_dataverse22 = require("@unseenco/theatre-dataverse");
8628
+
8629
+ // shared/src/gsap/syncGsapClipsAtSequencePosition.ts
8630
+ function syncGsapClipsAtSequencePosition(position, clips) {
8631
+ syncRegisteredGsapAnimationsForClips(
8632
+ position,
8633
+ clips
8634
+ );
8635
+ }
8636
+
8637
+ // shared/src/gsap/subscribeGsapClipSyncAtPlayhead.ts
8638
+ function subscribeGsapClipSyncAtPlayhead(source) {
8639
+ const positionPointer = source.pointer.position;
8640
+ const positionPrism = (0, import_theatre_dataverse22.pointerToPrism)(positionPointer);
8641
+ const clipsPrism = (0, import_theatre_dataverse22.prism)(() => source.getGsapClipTimings());
8642
+ const syncNow = () => {
8643
+ const clips = clipsPrism.getValue();
8644
+ if (clips.length === 0) return;
8645
+ syncGsapClipsAtSequencePosition((0, import_theatre_dataverse22.val)(positionPointer), clips);
8646
+ };
8647
+ const untapPosition = positionPrism.onStale(syncNow);
8648
+ const untapClips = clipsPrism.onStale(syncNow);
8649
+ syncNow();
8650
+ return () => {
8651
+ untapPosition();
8652
+ untapClips();
8653
+ };
8654
+ }
8655
+
8656
+ // core/src/gsap/attachGsapSequenceBridge.ts
8657
+ function attachGsapSequenceBridge(sheet) {
8658
+ const sequence = sheet.sequence;
8659
+ const sheetAddress = privateAPI(sheet).address;
8660
+ return subscribeGsapClipSyncAtPlayhead({
8661
+ pointer: sequence.pointer,
8662
+ getGsapClipTimings: () => sequence.__experimental_getGsapClips().map(({ objectKey, clip }) => ({
8663
+ sheetObjectAddressKey: sheetObjectAddressKeyFromParts({
8664
+ projectId: sheetAddress.projectId,
8665
+ sheetId: sheetAddress.sheetId,
8666
+ sheetInstanceId: sheetAddress.sheetInstanceId,
8667
+ objectKey
8668
+ }),
8669
+ gsapAnimationId: clip.gsapAnimationId,
8670
+ start: clip.start,
8671
+ duration: clip.duration,
8672
+ timelineChildren: clip.timelineChildren,
8673
+ timelineSpan: clip.timelineSpan
8674
+ }))
8675
+ });
8676
+ }
8677
+
8678
+ // core/src/coreExports.ts
8474
8679
  function getProject(id, config = {}) {
8475
8680
  const existingProject = projectsSingleton_default.get(id);
8476
8681
  if (existingProject) {
@@ -8550,10 +8755,10 @@ var validateProjectIdOrThrow = (value) => {
8550
8755
  };
8551
8756
  function onChange(pointer3, callback, rafDriver) {
8552
8757
  const ticker = rafDriver ? privateAPI(rafDriver).ticker : getCoreTicker();
8553
- if ((0, import_theatre_dataverse21.isPointer)(pointer3)) {
8554
- const pr = (0, import_theatre_dataverse22.pointerToPrism)(pointer3);
8758
+ if ((0, import_theatre_dataverse23.isPointer)(pointer3)) {
8759
+ const pr = (0, import_theatre_dataverse24.pointerToPrism)(pointer3);
8555
8760
  return pr.onChange(ticker, callback, true);
8556
- } else if ((0, import_theatre_dataverse22.isPrism)(pointer3)) {
8761
+ } else if ((0, import_theatre_dataverse24.isPrism)(pointer3)) {
8557
8762
  return pointer3.onChange(ticker, callback, true);
8558
8763
  } else {
8559
8764
  throw new Error(
@@ -8561,9 +8766,9 @@ function onChange(pointer3, callback, rafDriver) {
8561
8766
  );
8562
8767
  }
8563
8768
  }
8564
- function val10(pointer3) {
8565
- if ((0, import_theatre_dataverse21.isPointer)(pointer3)) {
8566
- return (0, import_theatre_dataverse22.pointerToPrism)(pointer3).getValue();
8769
+ function val11(pointer3) {
8770
+ if ((0, import_theatre_dataverse23.isPointer)(pointer3)) {
8771
+ return (0, import_theatre_dataverse24.pointerToPrism)(pointer3).getValue();
8567
8772
  } else {
8568
8773
  throw new Error("Called val(p) where p is not a pointer.");
8569
8774
  }
@@ -8578,7 +8783,7 @@ var CoreBundle = class {
8578
8783
  return "Theatre_CoreBundle";
8579
8784
  }
8580
8785
  get version() {
8581
- return "0.4.1";
8786
+ return "0.4.3";
8582
8787
  }
8583
8788
  getBitsForStudio(studio, callback) {
8584
8789
  if (this._studio) {