@unseenco/theatre-core 0.4.3 → 0.6.0

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.mjs CHANGED
@@ -239,17 +239,44 @@ var require_propose = __commonJS({
239
239
  // core/src/coreExports.ts
240
240
  var coreExports_exports = {};
241
241
  __export(coreExports_exports, {
242
+ PAGE_MODE_SEQUENCE_LENGTH: () => PAGE_MODE_SEQUENCE_LENGTH,
243
+ PAGE_MODE_SUB_UNITS_PER_UNIT: () => PAGE_MODE_SUB_UNITS_PER_UNIT,
242
244
  attachGsapSequenceBridge: () => attachGsapSequenceBridge,
245
+ attachSheetScrollDriver: () => attachSheetScrollDriver,
246
+ attachTheatrePageScroll: () => attachTheatrePageScroll,
247
+ configureTheatrePageScroll: () => configureTheatrePageScroll,
248
+ createDefaultPageScrollDriver: () => createDefaultPageScrollDriver,
249
+ createElementHorizontalScrollDriver: () => createElementHorizontalScrollDriver,
250
+ createElementScrollDriver: () => createElementScrollDriver,
251
+ createNativeDocumentHorizontalScrollDriver: () => createNativeDocumentHorizontalScrollDriver,
252
+ createNativeDocumentScrollDriver: () => createNativeDocumentScrollDriver,
243
253
  createRafDriver: () => createRafDriver,
254
+ defaultPageScrollContext: () => defaultPageScrollContext,
255
+ getActivePageScrollContext: () => getActivePageScrollContext,
244
256
  getProject: () => getProject,
257
+ getSheetScrollDriver: () => getSheetScrollDriver,
258
+ getTheatreCoreRafDriver: () => getTheatreCoreRafDriver,
259
+ getTheatrePageScrollConfig: () => getTheatrePageScrollConfig,
260
+ getTheatrePageScrollContext: () => getTheatrePageScrollContext,
261
+ isNativeDocumentScroller: () => isNativeDocumentScroller,
262
+ isPageScrollTrigger: () => isPageScrollTrigger,
245
263
  isRemoteEditorWindow: () => isRemoteEditorWindow,
264
+ isVerticalPageScrollTrigger: () => isVerticalPageScrollTrigger,
246
265
  notify: () => notify,
247
266
  onChange: () => onChange,
267
+ pageScrollProgressFromSequence: () => pageScrollProgressFromSequence,
268
+ pageScrollScrollersMatch: () => pageScrollScrollersMatch,
248
269
  privateAPI: () => privateAPI,
270
+ resolvePageScrollAxis: () => resolvePageScrollAxis,
271
+ resolvePageScrollScroller: () => resolvePageScrollScroller,
272
+ setActivePageScrollContext: () => setActivePageScrollContext,
249
273
  setCoreRafDriver: () => setCoreRafDriver,
274
+ setPageScrollProgress: () => setPageScrollProgress,
250
275
  setPrivateAPI: () => setPrivateAPI,
276
+ syncNativeDocumentScrollToSequencePosition: () => syncNativeDocumentScrollToSequencePosition,
277
+ syncPageScrollToSequencePosition: () => syncPageScrollToSequencePosition,
251
278
  types: () => propTypes_exports,
252
- val: () => val11
279
+ val: () => val14
253
280
  });
254
281
 
255
282
  // core/src/projects/projectsSingleton.ts
@@ -274,6 +301,82 @@ var ProjectsSingleton = class {
274
301
  var singleton = new ProjectsSingleton();
275
302
  var projectsSingleton_default = singleton;
276
303
 
304
+ // core/src/rafDrivers.ts
305
+ import { Ticker } from "@unseenco/theatre-dataverse";
306
+ var lastDriverId = 0;
307
+ function createRafDriver(conf) {
308
+ const tick = (time) => {
309
+ ticker.tick(time);
310
+ };
311
+ const ticker = new Ticker({
312
+ onActive() {
313
+ conf?.start?.();
314
+ },
315
+ onDormant() {
316
+ conf?.stop?.();
317
+ }
318
+ });
319
+ const driverPublicApi = {
320
+ tick,
321
+ id: lastDriverId++,
322
+ name: conf?.name ?? "CustomRafDriver-".concat(lastDriverId),
323
+ type: "Theatre_RafDriver_PublicAPI"
324
+ };
325
+ const driverPrivateApi = {
326
+ type: "Theatre_RafDriver_PrivateAPI",
327
+ publicApi: driverPublicApi,
328
+ ticker,
329
+ start: conf?.start,
330
+ stop: conf?.stop
331
+ };
332
+ setPrivateAPI(driverPublicApi, driverPrivateApi);
333
+ return driverPublicApi;
334
+ }
335
+
336
+ // core/src/coreTicker.ts
337
+ function createBasicRafDriver() {
338
+ let rafId = null;
339
+ const start = () => {
340
+ if (typeof window !== "undefined") {
341
+ const onAnimationFrame = (t2) => {
342
+ driver.tick(t2);
343
+ rafId = window.requestAnimationFrame(onAnimationFrame);
344
+ };
345
+ rafId = window.requestAnimationFrame(onAnimationFrame);
346
+ } else {
347
+ driver.tick(0);
348
+ setTimeout(() => driver.tick(1), 0);
349
+ }
350
+ };
351
+ const stop = () => {
352
+ if (typeof window !== "undefined") {
353
+ if (rafId !== null) {
354
+ window.cancelAnimationFrame(rafId);
355
+ }
356
+ } else {
357
+ }
358
+ };
359
+ const driver = createRafDriver({ name: "DefaultCoreRafDriver", start, stop });
360
+ return driver;
361
+ }
362
+ var coreRafDriver;
363
+ function getCoreRafDriver() {
364
+ if (!coreRafDriver) {
365
+ setCoreRafDriver(createBasicRafDriver());
366
+ }
367
+ return coreRafDriver;
368
+ }
369
+ function getCoreTicker() {
370
+ return getCoreRafDriver().ticker;
371
+ }
372
+ function setCoreRafDriver(driver) {
373
+ if (coreRafDriver) {
374
+ throw new Error("`setCoreRafDriver()` is already called.");
375
+ }
376
+ const driverPrivateApi = privateAPI(driver);
377
+ coreRafDriver = driverPrivateApi;
378
+ }
379
+
277
380
  // core/src/privateAPIs.ts
278
381
  var publicAPIToPrivateAPIMap = /* @__PURE__ */ new WeakMap();
279
382
  function privateAPI(pub) {
@@ -282,6 +385,23 @@ function privateAPI(pub) {
282
385
  function setPrivateAPI(pub, priv) {
283
386
  publicAPIToPrivateAPIMap.set(pub, priv);
284
387
  }
388
+ function getTheatreCoreRafDriver() {
389
+ return getCoreRafDriver().publicApi;
390
+ }
391
+
392
+ // core/src/sheets/applySheetRuntimeOptions.ts
393
+ function applySheetRuntimeOptions(sheet, opts) {
394
+ if (!opts) return;
395
+ if (opts.sequenceMode !== void 0) {
396
+ sheet.setSequenceMode(opts.sequenceMode);
397
+ }
398
+ if (opts.scrollDriver !== void 0) {
399
+ sheet.setPageScrollDriver(opts.scrollDriver);
400
+ }
401
+ if (opts.gsap === true) {
402
+ sheet.enableGsapSequenceBridge();
403
+ }
404
+ }
285
405
 
286
406
  // shared/src/utils/index.ts
287
407
  var emptyArray = [];
@@ -848,7 +968,7 @@ var SimpleCache = class {
848
968
  };
849
969
 
850
970
  // core/src/sheetObjects/SheetObjectTemplate.ts
851
- import { Atom as Atom4, getPointerParts as getPointerParts2, prism as prism5, val as val5 } from "@unseenco/theatre-dataverse";
971
+ import { Atom as Atom5, getPointerParts as getPointerParts2, prism as prism6, val as val6 } from "@unseenco/theatre-dataverse";
852
972
 
853
973
  // ../node_modules/lodash-es/_defineProperty.js
854
974
  var defineProperty = (function() {
@@ -959,181 +1079,6 @@ function generateDefaultsForCompound(config) {
959
1079
  return defaults;
960
1080
  }
961
1081
 
962
- // core/src/sequences/interpolationTripleAtPosition.ts
963
- var import_UnitBezier = __toESM(require_UnitBezier());
964
- import { prism, val } from "@unseenco/theatre-dataverse";
965
- function interpolationTripleAtPosition(ctx, trackP, timeD) {
966
- return prism(() => {
967
- const track = val(trackP);
968
- const driverD = prism.memo(
969
- "driver",
970
- () => {
971
- if (!track) {
972
- return prism(() => void 0);
973
- } else if (track.type === "BasicKeyframedTrack") {
974
- return _forKeyframedTrack(ctx, track, timeD);
975
- } else if (track.type === "GsapClipTrack") {
976
- return prism(() => void 0);
977
- } else {
978
- ctx.logger.error("Track type not yet supported.");
979
- return prism(() => void 0);
980
- }
981
- },
982
- [track]
983
- );
984
- return driverD.getValue();
985
- });
986
- }
987
- function _forKeyframedTrack(ctx, track, timeD) {
988
- return prism(() => {
989
- let stateRef = prism.ref("state", { started: false });
990
- let state = stateRef.current;
991
- const time = timeD.getValue();
992
- if (!state.started || time < state.validFrom || state.validTo <= time) {
993
- stateRef.current = state = updateState(ctx, timeD, track);
994
- }
995
- return state.der.getValue();
996
- });
997
- }
998
- var undefinedConstD = prism(() => void 0);
999
- function updateState(ctx, progressionD, track) {
1000
- const progression = progressionD.getValue();
1001
- if (track.keyframes.length === 0) {
1002
- return {
1003
- started: true,
1004
- validFrom: -Infinity,
1005
- validTo: Infinity,
1006
- der: undefinedConstD
1007
- };
1008
- }
1009
- let currentKeyframeIndex = 0;
1010
- while (true) {
1011
- const currentKeyframe = track.keyframes[currentKeyframeIndex];
1012
- if (!currentKeyframe) {
1013
- if (process.env.NODE_ENV !== "production") {
1014
- ctx.logger.error("Bug here");
1015
- }
1016
- return states.error;
1017
- }
1018
- const isLastKeyframe = currentKeyframeIndex === track.keyframes.length - 1;
1019
- if (progression < currentKeyframe.position) {
1020
- if (currentKeyframeIndex === 0) {
1021
- return states.beforeFirstKeyframe(currentKeyframe);
1022
- } else {
1023
- if (process.env.NODE_ENV !== "production") {
1024
- ctx.logger.error("Bug here");
1025
- }
1026
- return states.error;
1027
- }
1028
- } else if (currentKeyframe.position === progression) {
1029
- if (isLastKeyframe) {
1030
- return states.lastKeyframe(currentKeyframe);
1031
- } else {
1032
- return states.between(
1033
- currentKeyframe,
1034
- track.keyframes[currentKeyframeIndex + 1],
1035
- progressionD
1036
- );
1037
- }
1038
- } else {
1039
- if (currentKeyframeIndex === track.keyframes.length - 1) {
1040
- return states.lastKeyframe(currentKeyframe);
1041
- } else {
1042
- const nextKeyframeIndex = currentKeyframeIndex + 1;
1043
- if (track.keyframes[nextKeyframeIndex].position <= progression) {
1044
- currentKeyframeIndex = nextKeyframeIndex;
1045
- continue;
1046
- } else {
1047
- return states.between(
1048
- currentKeyframe,
1049
- track.keyframes[currentKeyframeIndex + 1],
1050
- progressionD
1051
- );
1052
- }
1053
- }
1054
- }
1055
- }
1056
- }
1057
- var states = {
1058
- beforeFirstKeyframe(kf) {
1059
- return {
1060
- started: true,
1061
- validFrom: -Infinity,
1062
- validTo: kf.position,
1063
- der: prism(() => ({ left: kf.value, progression: 0 }))
1064
- };
1065
- },
1066
- lastKeyframe(kf) {
1067
- return {
1068
- started: true,
1069
- validFrom: kf.position,
1070
- validTo: Infinity,
1071
- der: prism(() => ({ left: kf.value, progression: 0 }))
1072
- };
1073
- },
1074
- between(left, right, progressionD) {
1075
- if (!left.connectedRight) {
1076
- return {
1077
- started: true,
1078
- validFrom: left.position,
1079
- validTo: right.position,
1080
- der: prism(() => ({ left: left.value, progression: 0 }))
1081
- };
1082
- }
1083
- const globalProgressionToLocalProgression = (globalProgression) => {
1084
- return (globalProgression - left.position) / (right.position - left.position);
1085
- };
1086
- if (!left.type || left.type === "bezier") {
1087
- const solver = new import_UnitBezier.default(
1088
- left.handles[2],
1089
- left.handles[3],
1090
- right.handles[0],
1091
- right.handles[1]
1092
- );
1093
- const bezierDer = prism(() => {
1094
- const progression = globalProgressionToLocalProgression(
1095
- progressionD.getValue()
1096
- );
1097
- const valueProgression = solver.solveSimple(progression);
1098
- return {
1099
- left: left.value,
1100
- right: right.value,
1101
- progression: valueProgression
1102
- };
1103
- });
1104
- return {
1105
- started: true,
1106
- validFrom: left.position,
1107
- validTo: right.position,
1108
- der: bezierDer
1109
- };
1110
- }
1111
- const holdDer = prism(() => {
1112
- const progression = globalProgressionToLocalProgression(
1113
- progressionD.getValue()
1114
- );
1115
- const valueProgression = Math.floor(progression);
1116
- return {
1117
- left: left.value,
1118
- right: right.value,
1119
- progression: valueProgression
1120
- };
1121
- });
1122
- return {
1123
- started: true,
1124
- validFrom: left.position,
1125
- validTo: right.position,
1126
- der: holdDer
1127
- };
1128
- },
1129
- error: {
1130
- started: true,
1131
- validFrom: -Infinity,
1132
- validTo: Infinity,
1133
- der: undefinedConstD
1134
- }
1135
- };
1136
-
1137
1082
  // shared/src/utils/deepMergeWithCache.ts
1138
1083
  function deepMergeWithCache(base, override, cache2) {
1139
1084
  const _cache = cache2;
@@ -1165,24 +1110,24 @@ function pointerDeep(base, toAppend) {
1165
1110
  }
1166
1111
 
1167
1112
  // shared/src/utils/valToAtom.ts
1168
- import { Atom as Atom2, prism as prism2 } from "@unseenco/theatre-dataverse";
1113
+ import { Atom as Atom2, prism } from "@unseenco/theatre-dataverse";
1169
1114
  var valToAtom = (key, vals) => {
1170
- const a2 = prism2.memo(key, () => new Atom2(vals), []);
1115
+ const a2 = prism.memo(key, () => new Atom2(vals), []);
1171
1116
  a2.set(vals);
1172
1117
  return a2;
1173
1118
  };
1174
1119
 
1175
1120
  // core/src/sheetObjects/SheetObject.ts
1176
1121
  import {
1177
- Atom as Atom3,
1122
+ Atom as Atom4,
1178
1123
  getPointerParts,
1179
1124
  pointer,
1180
- prism as prism4,
1181
- val as val4
1125
+ prism as prism5,
1126
+ val as val5
1182
1127
  } from "@unseenco/theatre-dataverse";
1183
1128
 
1184
1129
  // core/src/sheetObjects/TheatreSheetObject.ts
1185
- import { prism as prism3, val as val2 } from "@unseenco/theatre-dataverse";
1130
+ import { prism as prism2, val } from "@unseenco/theatre-dataverse";
1186
1131
 
1187
1132
  // core/src/propTypes/index.ts
1188
1133
  var propTypes_exports = {};
@@ -3223,11 +3168,11 @@ function sanitizeCompoundProps(props) {
3223
3168
  );
3224
3169
  }
3225
3170
  }
3226
- const val12 = props[key];
3227
- if (isLonghandPropType(val12)) {
3228
- sanitizedProps[key] = val12;
3171
+ const val15 = props[key];
3172
+ if (isLonghandPropType(val15)) {
3173
+ sanitizedProps[key] = val15;
3229
3174
  } else {
3230
- sanitizedProps[key] = toLonghandProp(val12);
3175
+ sanitizedProps[key] = toLonghandProp(val15);
3231
3176
  }
3232
3177
  }
3233
3178
  return sanitizedProps;
@@ -3325,15 +3270,15 @@ var file = (defaultValue, opts = {}) => {
3325
3270
  deserializeAndSanitize: _ensureFile
3326
3271
  };
3327
3272
  };
3328
- var _ensureFile = (val12) => {
3329
- if (!val12) return void 0;
3273
+ var _ensureFile = (val15) => {
3274
+ if (!val15) return void 0;
3330
3275
  let valid = true;
3331
- if (typeof val12.id !== "string" && ![null, void 0].includes(val12.id)) {
3276
+ if (typeof val15.id !== "string" && ![null, void 0].includes(val15.id)) {
3332
3277
  valid = false;
3333
3278
  }
3334
- if (val12.type !== "file") valid = false;
3279
+ if (val15.type !== "file") valid = false;
3335
3280
  if (!valid) return void 0;
3336
- return val12;
3281
+ return val15;
3337
3282
  };
3338
3283
  var image = (defaultValue, opts = {}) => {
3339
3284
  if (process.env.NODE_ENV !== "production") {
@@ -3357,15 +3302,15 @@ var image = (defaultValue, opts = {}) => {
3357
3302
  deserializeAndSanitize: _ensureImage
3358
3303
  };
3359
3304
  };
3360
- var _ensureImage = (val12) => {
3361
- if (!val12) return void 0;
3305
+ var _ensureImage = (val15) => {
3306
+ if (!val15) return void 0;
3362
3307
  let valid = true;
3363
- if (typeof val12.id !== "string" && ![null, void 0].includes(val12.id)) {
3308
+ if (typeof val15.id !== "string" && ![null, void 0].includes(val15.id)) {
3364
3309
  valid = false;
3365
3310
  }
3366
- if (val12.type !== "image") valid = false;
3311
+ if (val15.type !== "image") valid = false;
3367
3312
  if (!valid) return void 0;
3368
- return val12;
3313
+ return val15;
3369
3314
  };
3370
3315
  var number = (defaultValue, opts = {}) => {
3371
3316
  if (process.env.NODE_ENV !== "production") {
@@ -3488,11 +3433,11 @@ var rgba = (defaultValue = { r: 0, g: 0, b: 0, a: 1 }, opts = {}) => {
3488
3433
  deserializeAndSanitize: _sanitizeRgba
3489
3434
  };
3490
3435
  };
3491
- var _sanitizeRgba = (val12) => {
3492
- if (!val12) return void 0;
3436
+ var _sanitizeRgba = (val15) => {
3437
+ if (!val15) return void 0;
3493
3438
  let valid = true;
3494
3439
  for (const c2 of ["r", "g", "b", "a"]) {
3495
- if (!Object.prototype.hasOwnProperty.call(val12, c2) || typeof val12[c2] !== "number") {
3440
+ if (!Object.prototype.hasOwnProperty.call(val15, c2) || typeof val15[c2] !== "number") {
3496
3441
  valid = false;
3497
3442
  }
3498
3443
  }
@@ -3501,7 +3446,7 @@ var _sanitizeRgba = (val12) => {
3501
3446
  for (const c2 of ["r", "g", "b", "a"]) {
3502
3447
  ;
3503
3448
  sanitized[c2] = Math.min(
3504
- Math.max(val12[c2], 0),
3449
+ Math.max(val15[c2], 0),
3505
3450
  1
3506
3451
  );
3507
3452
  }
@@ -3540,8 +3485,8 @@ var boolean = (defaultValue, opts = {}) => {
3540
3485
  deserializeAndSanitize: _ensureBoolean
3541
3486
  };
3542
3487
  };
3543
- var _ensureBoolean = (val12) => {
3544
- return typeof val12 === "boolean" ? val12 : void 0;
3488
+ var _ensureBoolean = (val15) => {
3489
+ return typeof val15 === "boolean" ? val15 : void 0;
3545
3490
  };
3546
3491
  function leftInterpolate(left) {
3547
3492
  return left;
@@ -3699,8 +3644,8 @@ var TheatreSheetObject = class {
3699
3644
  _valuesPrism() {
3700
3645
  return this._cache.get("_valuesPrism", () => {
3701
3646
  const sheetObject = privateAPI(this);
3702
- const d2 = prism3(() => {
3703
- return val2(sheetObject.getValues().getValue());
3647
+ const d2 = prism2(() => {
3648
+ return val(sheetObject.getValues().getValue());
3704
3649
  });
3705
3650
  return d2;
3706
3651
  });
@@ -3708,10 +3653,10 @@ var TheatreSheetObject = class {
3708
3653
  _valuesWithVariantPrism() {
3709
3654
  return this._cache.get("_valuesWithVariantPrism", () => {
3710
3655
  const sheetObject = privateAPI(this);
3711
- return prism3(() => {
3656
+ return prism2(() => {
3712
3657
  return {
3713
- values: val2(sheetObject.getValues().getValue()),
3714
- variant: val2(sheetObject.sheet.effectiveActiveSequenceVariantD)
3658
+ values: val(sheetObject.getValues().getValue()),
3659
+ variant: val(sheetObject.sheet.effectiveActiveSequenceVariantD)
3715
3660
  };
3716
3661
  });
3717
3662
  });
@@ -3748,8 +3693,8 @@ var TheatreSheetObject = class {
3748
3693
  }
3749
3694
  return der.getValue();
3750
3695
  }
3751
- set initialValue(val12) {
3752
- privateAPI(this).setInitialValue(val12);
3696
+ set initialValue(val15) {
3697
+ privateAPI(this).setInitialValue(val15);
3753
3698
  }
3754
3699
  showPropsOf(objects) {
3755
3700
  const host = privateAPI(this);
@@ -3789,19 +3734,197 @@ var TheatreSheetObject = class {
3789
3734
  }
3790
3735
  };
3791
3736
 
3792
- // shared/src/propTypes/utils.ts
3793
- var import_fast_deep_equal = __toESM(require_fast_deep_equal());
3794
-
3795
- // shared/src/utils/memoizeFn.ts
3796
- function memoizeFn(producer) {
3797
- const cache2 = /* @__PURE__ */ new WeakMap();
3798
- return (k2) => {
3799
- if (!cache2.has(k2)) {
3800
- cache2.set(k2, producer(k2));
3801
- }
3802
- return cache2.get(k2);
3803
- };
3804
- }
3737
+ // core/src/sequences/interpolationTripleAtPosition.ts
3738
+ var import_UnitBezier = __toESM(require_UnitBezier());
3739
+ import { prism as prism3, val as val2 } from "@unseenco/theatre-dataverse";
3740
+ function interpolationTripleAtPosition(ctx, trackP, timeD) {
3741
+ return prism3(() => {
3742
+ const track = val2(trackP);
3743
+ const driverD = prism3.memo(
3744
+ "driver",
3745
+ () => {
3746
+ if (!track) {
3747
+ return prism3(() => void 0);
3748
+ } else if (track.type === "BasicKeyframedTrack") {
3749
+ return _forKeyframedTrack(ctx, track, timeD);
3750
+ } else if (track.type === "GsapClipTrack") {
3751
+ return prism3(() => void 0);
3752
+ } else {
3753
+ ctx.logger.error("Track type not yet supported.");
3754
+ return prism3(() => void 0);
3755
+ }
3756
+ },
3757
+ [track]
3758
+ );
3759
+ return driverD.getValue();
3760
+ });
3761
+ }
3762
+ function _forKeyframedTrack(ctx, track, timeD) {
3763
+ return prism3(() => {
3764
+ let stateRef = prism3.ref("state", { started: false });
3765
+ let state = stateRef.current;
3766
+ const time = timeD.getValue();
3767
+ if (!state.started || time < state.validFrom || state.validTo <= time) {
3768
+ stateRef.current = state = updateState(ctx, timeD, track);
3769
+ }
3770
+ return state.der.getValue();
3771
+ });
3772
+ }
3773
+ var undefinedConstD = prism3(() => void 0);
3774
+ function updateState(ctx, progressionD, track) {
3775
+ const progression = progressionD.getValue();
3776
+ if (track.keyframes.length === 0) {
3777
+ return {
3778
+ started: true,
3779
+ validFrom: -Infinity,
3780
+ validTo: Infinity,
3781
+ der: undefinedConstD
3782
+ };
3783
+ }
3784
+ let currentKeyframeIndex = 0;
3785
+ while (true) {
3786
+ const currentKeyframe = track.keyframes[currentKeyframeIndex];
3787
+ if (!currentKeyframe) {
3788
+ if (process.env.NODE_ENV !== "production") {
3789
+ ctx.logger.error("Bug here");
3790
+ }
3791
+ return states.error;
3792
+ }
3793
+ const isLastKeyframe = currentKeyframeIndex === track.keyframes.length - 1;
3794
+ if (progression < currentKeyframe.position) {
3795
+ if (currentKeyframeIndex === 0) {
3796
+ return states.beforeFirstKeyframe(currentKeyframe);
3797
+ } else {
3798
+ if (process.env.NODE_ENV !== "production") {
3799
+ ctx.logger.error("Bug here");
3800
+ }
3801
+ return states.error;
3802
+ }
3803
+ } else if (currentKeyframe.position === progression) {
3804
+ if (isLastKeyframe) {
3805
+ return states.lastKeyframe(currentKeyframe);
3806
+ } else {
3807
+ return states.between(
3808
+ currentKeyframe,
3809
+ track.keyframes[currentKeyframeIndex + 1],
3810
+ progressionD
3811
+ );
3812
+ }
3813
+ } else {
3814
+ if (currentKeyframeIndex === track.keyframes.length - 1) {
3815
+ return states.lastKeyframe(currentKeyframe);
3816
+ } else {
3817
+ const nextKeyframeIndex = currentKeyframeIndex + 1;
3818
+ if (track.keyframes[nextKeyframeIndex].position <= progression) {
3819
+ currentKeyframeIndex = nextKeyframeIndex;
3820
+ continue;
3821
+ } else {
3822
+ return states.between(
3823
+ currentKeyframe,
3824
+ track.keyframes[currentKeyframeIndex + 1],
3825
+ progressionD
3826
+ );
3827
+ }
3828
+ }
3829
+ }
3830
+ }
3831
+ }
3832
+ var states = {
3833
+ beforeFirstKeyframe(kf) {
3834
+ return {
3835
+ started: true,
3836
+ validFrom: -Infinity,
3837
+ validTo: kf.position,
3838
+ der: prism3(() => ({ left: kf.value, progression: 0 }))
3839
+ };
3840
+ },
3841
+ lastKeyframe(kf) {
3842
+ return {
3843
+ started: true,
3844
+ validFrom: kf.position,
3845
+ validTo: Infinity,
3846
+ der: prism3(() => ({ left: kf.value, progression: 0 }))
3847
+ };
3848
+ },
3849
+ between(left, right, progressionD) {
3850
+ if (!left.connectedRight) {
3851
+ return {
3852
+ started: true,
3853
+ validFrom: left.position,
3854
+ validTo: right.position,
3855
+ der: prism3(() => ({ left: left.value, progression: 0 }))
3856
+ };
3857
+ }
3858
+ const globalProgressionToLocalProgression = (globalProgression) => {
3859
+ return (globalProgression - left.position) / (right.position - left.position);
3860
+ };
3861
+ if (!left.type || left.type === "bezier") {
3862
+ const solver = new import_UnitBezier.default(
3863
+ left.handles[2],
3864
+ left.handles[3],
3865
+ right.handles[0],
3866
+ right.handles[1]
3867
+ );
3868
+ const bezierDer = prism3(() => {
3869
+ const progression = globalProgressionToLocalProgression(
3870
+ progressionD.getValue()
3871
+ );
3872
+ const valueProgression = solver.solveSimple(progression);
3873
+ return {
3874
+ left: left.value,
3875
+ right: right.value,
3876
+ progression: valueProgression
3877
+ };
3878
+ });
3879
+ return {
3880
+ started: true,
3881
+ validFrom: left.position,
3882
+ validTo: right.position,
3883
+ der: bezierDer
3884
+ };
3885
+ }
3886
+ const holdDer = prism3(() => {
3887
+ const progression = globalProgressionToLocalProgression(
3888
+ progressionD.getValue()
3889
+ );
3890
+ const valueProgression = Math.floor(progression);
3891
+ return {
3892
+ left: left.value,
3893
+ right: right.value,
3894
+ progression: valueProgression
3895
+ };
3896
+ });
3897
+ return {
3898
+ started: true,
3899
+ validFrom: left.position,
3900
+ validTo: right.position,
3901
+ der: holdDer
3902
+ };
3903
+ },
3904
+ error: {
3905
+ started: true,
3906
+ validFrom: -Infinity,
3907
+ validTo: Infinity,
3908
+ der: undefinedConstD
3909
+ }
3910
+ };
3911
+
3912
+ // core/src/sheetObjects/sheetObjectSequencedFull.ts
3913
+ import { Atom as Atom3, prism as prism4, val as val4 } from "@unseenco/theatre-dataverse";
3914
+
3915
+ // shared/src/propTypes/utils.ts
3916
+ var import_fast_deep_equal = __toESM(require_fast_deep_equal());
3917
+
3918
+ // shared/src/utils/memoizeFn.ts
3919
+ function memoizeFn(producer) {
3920
+ const cache2 = /* @__PURE__ */ new WeakMap();
3921
+ return (k2) => {
3922
+ if (!cache2.has(k2)) {
3923
+ cache2.set(k2, producer(k2));
3924
+ }
3925
+ return cache2.get(k2);
3926
+ };
3927
+ }
3805
3928
 
3806
3929
  // shared/src/utils/addresses.ts
3807
3930
  var encodePathToProp = memoizeFn(
@@ -4106,43 +4229,6 @@ function* iteratePropType(conf, pathPrefix) {
4106
4229
  }
4107
4230
  }
4108
4231
 
4109
- // shared/src/utils/updateDeep.ts
4110
- function updateDeep(obj, path, reducer) {
4111
- if (path.length === 0) return reducer(obj);
4112
- return hoop(obj, path, reducer);
4113
- }
4114
- var hoop = (s2, path, reducer) => {
4115
- if (path.length === 0) {
4116
- return reducer(s2);
4117
- }
4118
- if (Array.isArray(s2)) {
4119
- let [index, ...restOfPath] = path;
4120
- index = parseInt(String(index), 10);
4121
- if (isNaN(index)) index = 0;
4122
- const oldVal = s2[index];
4123
- const newVal = hoop(oldVal, restOfPath, reducer);
4124
- if (oldVal === newVal) return s2;
4125
- const newS = [...s2];
4126
- newS.splice(index, 1, newVal);
4127
- return newS;
4128
- } else if (typeof s2 === "object" && s2 !== null) {
4129
- const [key, ...restOfPath] = path;
4130
- const oldVal = s2[key];
4131
- const newVal = hoop(oldVal, restOfPath, reducer);
4132
- if (oldVal === newVal) return s2;
4133
- const newS = { ...s2, [key]: newVal };
4134
- return newS;
4135
- } else {
4136
- const [key, ...restOfPath] = path;
4137
- return { [key]: hoop(void 0, restOfPath, reducer) };
4138
- }
4139
- };
4140
-
4141
- // shared/src/utils/setDeepImmutable.ts
4142
- function setDeepImmutable(obj, path, replace) {
4143
- return updateDeep(obj, path, () => replace);
4144
- }
4145
-
4146
4232
  // core/src/sequences/sequenceVariants.ts
4147
4233
  import { val as val3 } from "@unseenco/theatre-dataverse";
4148
4234
 
@@ -4296,64 +4382,196 @@ function validateSequenceVariantsOrThrow(variants, fnName) {
4296
4382
  return sanitized;
4297
4383
  }
4298
4384
 
4299
- // core/src/sheetObjects/SheetObject.ts
4300
- var SheetObject = class {
4301
- constructor(sheet, template, nativeObject) {
4302
- this.sheet = sheet;
4303
- this.template = template;
4304
- this.nativeObject = nativeObject;
4305
- __publicField(this, "$$isPointerToPrismProvider", true);
4306
- __publicField(this, "address");
4307
- __publicField(this, "publicApi");
4308
- __publicField(this, "_initialValue", new Atom3({}));
4309
- /**
4310
- * Highest-priority override layer, written to by `RemoteSync` when a value
4311
- * update arrives from a remote editor window (see `internal/RemoteSync.ts`).
4312
- * Empty (`{}`) unless a remote editor is actually connected, so it's a
4313
- * no-op merge for every app that never uses the remote-sync feature.
4314
- */
4315
- __publicField(this, "_remoteOverride", new Atom3({}));
4316
- /**
4317
- * Session-only overrides for props with `persist: false`. Not written to
4318
- * persisted project state and cleared on refresh.
4319
- */
4320
- __publicField(this, "_sessionOverrides", new Atom3({}));
4321
- __publicField(this, "_cache", new SimpleCache());
4322
- __publicField(this, "_logger");
4323
- __publicField(this, "_internalUtilCtx");
4324
- this._logger = sheet._logger.named(
4325
- "SheetObject",
4326
- template.address.objectKey
4385
+ // core/src/sheetObjects/sheetObjectSequencedFull.ts
4386
+ function trackIdToPrism(obj, trackId, trackVariant) {
4387
+ const activeVariant = val4(obj.sheet.effectiveActiveSequenceVariantD);
4388
+ const trackP = pointerToSequenceTrackData(
4389
+ obj.template.project.pointers.historic.sheetsById[obj.address.sheetId],
4390
+ trackVariant,
4391
+ obj.address.objectKey,
4392
+ trackId
4393
+ );
4394
+ const timeD = obj.sheet.getSequence(activeVariant).positionPrism;
4395
+ return interpolationTripleAtPosition(obj._internalUtilCtx, trackP, timeD);
4396
+ }
4397
+ function getSequencedValues(obj) {
4398
+ return prism4(() => {
4399
+ const activeVariant = val4(obj.sheet.effectiveActiveSequenceVariantD);
4400
+ const sequenceVariant = isSheetPropsObjectKey(obj.address.objectKey) ? DEFAULT_SEQUENCE_VARIANT : activeVariant;
4401
+ const tracksToProcessD = prism4.memo(
4402
+ "tracksToProcess",
4403
+ () => obj.template.getArrayOfValidSequenceTracks(sequenceVariant),
4404
+ [sequenceVariant]
4327
4405
  );
4328
- this._logger._trace("creating object");
4329
- this._internalUtilCtx = { logger: this._logger.utilFor.internal() };
4330
- this.address = {
4331
- ...template.address,
4332
- sheetInstanceId: sheet.address.sheetInstanceId
4333
- };
4334
- this.publicApi = new TheatreSheetObject(this);
4335
- }
4336
- get type() {
4337
- return "Theatre_SheetObject";
4338
- }
4339
- getValues() {
4340
- return this._cache.get(
4341
- "getValues()",
4342
- () => prism4(() => {
4343
- const defaults = val4(this.template.getDefaultValues());
4344
- const initial = val4(this._initialValue.pointer);
4345
- const withInitialCache = prism4.memo(
4346
- "withInitialCache",
4347
- () => /* @__PURE__ */ new WeakMap(),
4348
- []
4349
- );
4406
+ const tracksToProcess = val4(tracksToProcessD);
4407
+ const valsAtom = new Atom3({});
4408
+ const config = val4(obj.template.configPointer);
4409
+ prism4.effect(
4410
+ "processTracks",
4411
+ () => {
4412
+ const untaps = [];
4413
+ for (const { trackId, pathToProp, trackVariant } of tracksToProcess) {
4414
+ if (obj.template.isNonSequencablePropPath(pathToProp)) continue;
4415
+ const pr = trackIdToPrism(obj, trackId, trackVariant);
4416
+ const propConfig = getPropConfigByPath(
4417
+ config,
4418
+ pathToProp
4419
+ );
4420
+ const deserializeAndSanitize = propConfig.deserializeAndSanitize;
4421
+ const interpolate = propConfig.interpolate;
4422
+ const updateSequenceValueFromItsPrism = () => {
4423
+ const triple = pr.getValue();
4424
+ if (!triple)
4425
+ return valsAtom.setByPointer(
4426
+ (p2) => pointerDeep(p2, pathToProp),
4427
+ void 0
4428
+ );
4429
+ const leftDeserialized = deserializeAndSanitize(triple.left);
4430
+ const left = leftDeserialized === void 0 ? propConfig.default : leftDeserialized;
4431
+ if (triple.right === void 0)
4432
+ return valsAtom.setByPointer(
4433
+ (p2) => pointerDeep(p2, pathToProp),
4434
+ left
4435
+ );
4436
+ const rightDeserialized = deserializeAndSanitize(triple.right);
4437
+ const right = rightDeserialized === void 0 ? propConfig.default : rightDeserialized;
4438
+ return valsAtom.setByPointer(
4439
+ (p2) => pointerDeep(p2, pathToProp),
4440
+ interpolate(left, right, triple.progression)
4441
+ );
4442
+ };
4443
+ const untap = pr.onStale(updateSequenceValueFromItsPrism);
4444
+ updateSequenceValueFromItsPrism();
4445
+ untaps.push(untap);
4446
+ }
4447
+ return () => {
4448
+ for (const untap of untaps) {
4449
+ untap();
4450
+ }
4451
+ };
4452
+ },
4453
+ [config, ...tracksToProcess]
4454
+ );
4455
+ return valsAtom.pointer;
4456
+ });
4457
+ }
4458
+ function mergeSequencedValuesIntoFinal(obj, base, withSeqsCache) {
4459
+ const pointerToSequencedValuesD = prism4.memo(
4460
+ "seq",
4461
+ () => getSequencedValues(obj),
4462
+ []
4463
+ );
4464
+ const sequenced = val4(val4(pointerToSequencedValuesD));
4465
+ return deepMergeWithCache(base, sequenced, withSeqsCache);
4466
+ }
4467
+
4468
+ // core/src/utils/isTheatreLiteMode.ts
4469
+ function isTheatreLiteMode() {
4470
+ if (false) {
4471
+ return true;
4472
+ }
4473
+ if (typeof globalThis !== "undefined") {
4474
+ return !!globalThis.__THEATRE_FORCE_LITE__;
4475
+ }
4476
+ return false;
4477
+ }
4478
+
4479
+ // shared/src/utils/updateDeep.ts
4480
+ function updateDeep(obj, path, reducer) {
4481
+ if (path.length === 0) return reducer(obj);
4482
+ return hoop(obj, path, reducer);
4483
+ }
4484
+ var hoop = (s2, path, reducer) => {
4485
+ if (path.length === 0) {
4486
+ return reducer(s2);
4487
+ }
4488
+ if (Array.isArray(s2)) {
4489
+ let [index, ...restOfPath] = path;
4490
+ index = parseInt(String(index), 10);
4491
+ if (isNaN(index)) index = 0;
4492
+ const oldVal = s2[index];
4493
+ const newVal = hoop(oldVal, restOfPath, reducer);
4494
+ if (oldVal === newVal) return s2;
4495
+ const newS = [...s2];
4496
+ newS.splice(index, 1, newVal);
4497
+ return newS;
4498
+ } else if (typeof s2 === "object" && s2 !== null) {
4499
+ const [key, ...restOfPath] = path;
4500
+ const oldVal = s2[key];
4501
+ const newVal = hoop(oldVal, restOfPath, reducer);
4502
+ if (oldVal === newVal) return s2;
4503
+ const newS = { ...s2, [key]: newVal };
4504
+ return newS;
4505
+ } else {
4506
+ const [key, ...restOfPath] = path;
4507
+ return { [key]: hoop(void 0, restOfPath, reducer) };
4508
+ }
4509
+ };
4510
+
4511
+ // shared/src/utils/setDeepImmutable.ts
4512
+ function setDeepImmutable(obj, path, replace) {
4513
+ return updateDeep(obj, path, () => replace);
4514
+ }
4515
+
4516
+ // core/src/sheetObjects/SheetObject.ts
4517
+ var SheetObject = class {
4518
+ constructor(sheet, template, nativeObject) {
4519
+ this.sheet = sheet;
4520
+ this.template = template;
4521
+ this.nativeObject = nativeObject;
4522
+ __publicField(this, "$$isPointerToPrismProvider", true);
4523
+ __publicField(this, "address");
4524
+ __publicField(this, "publicApi");
4525
+ __publicField(this, "_initialValue", new Atom4({}));
4526
+ /**
4527
+ * Highest-priority override layer, written to by `RemoteSync` when a value
4528
+ * update arrives from a remote editor window (see `internal/RemoteSync.ts`).
4529
+ * Empty (`{}`) unless a remote editor is actually connected, so it's a
4530
+ * no-op merge for every app that never uses the remote-sync feature.
4531
+ */
4532
+ __publicField(this, "_remoteOverride", new Atom4({}));
4533
+ /**
4534
+ * Session-only overrides for props with `persist: false`. Not written to
4535
+ * persisted project state and cleared on refresh.
4536
+ */
4537
+ __publicField(this, "_sessionOverrides", new Atom4({}));
4538
+ __publicField(this, "_cache", new SimpleCache());
4539
+ __publicField(this, "_logger");
4540
+ /** @internal Used by `sheetObjectSequencedFull`. */
4541
+ __publicField(this, "_internalUtilCtx");
4542
+ this._logger = sheet._logger.named(
4543
+ "SheetObject",
4544
+ template.address.objectKey
4545
+ );
4546
+ this._logger._trace("creating object");
4547
+ this._internalUtilCtx = { logger: this._logger.utilFor.internal() };
4548
+ this.address = {
4549
+ ...template.address,
4550
+ sheetInstanceId: sheet.address.sheetInstanceId
4551
+ };
4552
+ this.publicApi = new TheatreSheetObject(this);
4553
+ }
4554
+ get type() {
4555
+ return "Theatre_SheetObject";
4556
+ }
4557
+ getValues() {
4558
+ return this._cache.get(
4559
+ "getValues()",
4560
+ () => prism5(() => {
4561
+ const defaults = val5(this.template.getDefaultValues());
4562
+ const initial = val5(this._initialValue.pointer);
4563
+ const withInitialCache = prism5.memo(
4564
+ "withInitialCache",
4565
+ () => /* @__PURE__ */ new WeakMap(),
4566
+ []
4567
+ );
4350
4568
  const withInitial = deepMergeWithCache(
4351
4569
  defaults,
4352
4570
  initial,
4353
4571
  withInitialCache
4354
4572
  );
4355
- const ahistoricStatics = val4(this.template.getAhistoricStaticValues());
4356
- const withAhistoricStaticsCache = prism4.memo(
4573
+ const ahistoricStatics = val5(this.template.getAhistoricStaticValues());
4574
+ const withAhistoricStaticsCache = prism5.memo(
4357
4575
  "withAhistoricStatics",
4358
4576
  () => /* @__PURE__ */ new WeakMap(),
4359
4577
  []
@@ -4363,10 +4581,10 @@ var SheetObject = class {
4363
4581
  ahistoricStatics,
4364
4582
  withAhistoricStaticsCache
4365
4583
  );
4366
- const activeVariant = val4(this.sheet.effectiveActiveSequenceVariantD);
4584
+ const activeVariant = val5(this.sheet.effectiveActiveSequenceVariantD);
4367
4585
  const staticVariant = isSheetPropsObjectKey(this.address.objectKey) ? DEFAULT_SEQUENCE_VARIANT : activeVariant;
4368
- const statics = val4(this.template.getStaticValues(staticVariant));
4369
- const withStaticsCache = prism4.memo(
4586
+ const statics = val5(this.template.getStaticValues(staticVariant));
4587
+ const withStaticsCache = prism5.memo(
4370
4588
  "withStatics",
4371
4589
  () => /* @__PURE__ */ new WeakMap(),
4372
4590
  []
@@ -4377,24 +4595,16 @@ var SheetObject = class {
4377
4595
  withStaticsCache
4378
4596
  );
4379
4597
  let final = withStatics;
4380
- let sequenced;
4381
- {
4382
- const pointerToSequencedValuesD = prism4.memo(
4383
- "seq",
4384
- () => this.getSequencedValues(),
4385
- []
4386
- );
4387
- const withSeqsCache = prism4.memo(
4598
+ if (!isTheatreLiteMode()) {
4599
+ const withSeqsCache = prism5.memo(
4388
4600
  "withSeqsCache",
4389
4601
  () => /* @__PURE__ */ new WeakMap(),
4390
4602
  []
4391
4603
  );
4392
- sequenced = val4(val4(pointerToSequencedValuesD));
4393
- const withSeqs = deepMergeWithCache(final, sequenced, withSeqsCache);
4394
- final = withSeqs;
4604
+ final = mergeSequencedValuesIntoFinal(this, final, withSeqsCache);
4395
4605
  }
4396
- const sessionOverrides = val4(this._sessionOverrides.pointer);
4397
- const withSessionOverridesCache = prism4.memo(
4606
+ const sessionOverrides = val5(this._sessionOverrides.pointer);
4607
+ const withSessionOverridesCache = prism5.memo(
4398
4608
  "withSessionOverridesCache",
4399
4609
  () => /* @__PURE__ */ new WeakMap(),
4400
4610
  []
@@ -4404,8 +4614,8 @@ var SheetObject = class {
4404
4614
  sessionOverrides,
4405
4615
  withSessionOverridesCache
4406
4616
  );
4407
- const remoteOverride = val4(this._remoteOverride.pointer);
4408
- const withRemoteOverrideCache = prism4.memo(
4617
+ const remoteOverride = val5(this._remoteOverride.pointer);
4618
+ const withRemoteOverrideCache = prism5.memo(
4409
4619
  "withRemoteOverrideCache",
4410
4620
  () => /* @__PURE__ */ new WeakMap(),
4411
4621
  []
@@ -4420,106 +4630,31 @@ var SheetObject = class {
4420
4630
  })
4421
4631
  );
4422
4632
  }
4423
- getValueByPointer(pointer3) {
4424
- const allValuesP = val4(this.getValues());
4425
- const { path } = getPointerParts(pointer3);
4426
- return val4(
4633
+ getValueByPointer(pointer4) {
4634
+ const allValuesP = val5(this.getValues());
4635
+ const { path } = getPointerParts(pointer4);
4636
+ return val5(
4427
4637
  pointerDeep(allValuesP, path)
4428
4638
  );
4429
4639
  }
4430
- pointerToPrism(pointer3) {
4431
- const { path } = getPointerParts(pointer3);
4432
- return prism4(() => {
4433
- const allValuesP = val4(this.getValues());
4434
- return val4(pointerDeep(allValuesP, path));
4435
- });
4436
- }
4437
- /**
4438
- * Returns values of props that are sequenced.
4439
- */
4440
- getSequencedValues() {
4441
- return prism4(() => {
4442
- const activeVariant = val4(this.sheet.effectiveActiveSequenceVariantD);
4443
- const sequenceVariant = isSheetPropsObjectKey(this.address.objectKey) ? DEFAULT_SEQUENCE_VARIANT : activeVariant;
4444
- const tracksToProcessD = prism4.memo(
4445
- "tracksToProcess",
4446
- () => this.template.getArrayOfValidSequenceTracks(sequenceVariant),
4447
- [sequenceVariant]
4448
- );
4449
- const tracksToProcess = val4(tracksToProcessD);
4450
- const valsAtom = new Atom3({});
4451
- const config = val4(this.template.configPointer);
4452
- prism4.effect(
4453
- "processTracks",
4454
- () => {
4455
- const untaps = [];
4456
- for (const { trackId, pathToProp, trackVariant } of tracksToProcess) {
4457
- if (this.template.isNonSequencablePropPath(pathToProp)) continue;
4458
- const pr = this._trackIdToPrism(trackId, trackVariant);
4459
- const propConfig = getPropConfigByPath(
4460
- config,
4461
- pathToProp
4462
- );
4463
- const deserializeAndSanitize = propConfig.deserializeAndSanitize;
4464
- const interpolate = propConfig.interpolate;
4465
- const updateSequenceValueFromItsPrism = () => {
4466
- const triple = pr.getValue();
4467
- if (!triple)
4468
- return valsAtom.setByPointer(
4469
- (p2) => pointerDeep(p2, pathToProp),
4470
- void 0
4471
- );
4472
- const leftDeserialized = deserializeAndSanitize(triple.left);
4473
- const left = leftDeserialized === void 0 ? propConfig.default : leftDeserialized;
4474
- if (triple.right === void 0)
4475
- return valsAtom.setByPointer(
4476
- (p2) => pointerDeep(p2, pathToProp),
4477
- left
4478
- );
4479
- const rightDeserialized = deserializeAndSanitize(triple.right);
4480
- const right = rightDeserialized === void 0 ? propConfig.default : rightDeserialized;
4481
- return valsAtom.setByPointer(
4482
- (p2) => pointerDeep(p2, pathToProp),
4483
- interpolate(left, right, triple.progression)
4484
- );
4485
- };
4486
- const untap = pr.onStale(updateSequenceValueFromItsPrism);
4487
- updateSequenceValueFromItsPrism();
4488
- untaps.push(untap);
4489
- }
4490
- return () => {
4491
- for (const untap of untaps) {
4492
- untap();
4493
- }
4494
- };
4495
- },
4496
- [config, ...tracksToProcess]
4497
- );
4498
- return valsAtom.pointer;
4640
+ pointerToPrism(pointer4) {
4641
+ const { path } = getPointerParts(pointer4);
4642
+ return prism5(() => {
4643
+ const allValuesP = val5(this.getValues());
4644
+ return val5(pointerDeep(allValuesP, path));
4499
4645
  });
4500
4646
  }
4501
- _trackIdToPrism(trackId, trackVariant) {
4502
- const activeVariant = val4(this.sheet.effectiveActiveSequenceVariantD);
4503
- const trackP = pointerToSequenceTrackData(
4504
- this.template.project.pointers.historic.sheetsById[this.address.sheetId],
4505
- trackVariant,
4506
- this.address.objectKey,
4507
- trackId
4508
- );
4509
- const timeD = this.sheet.getSequence(activeVariant).positionPrism;
4510
- return interpolationTripleAtPosition(this._internalUtilCtx, trackP, timeD);
4511
- }
4512
4647
  get propsP() {
4513
4648
  return this._cache.get(
4514
4649
  "propsP",
4515
4650
  () => pointer({ root: this, path: [] })
4516
4651
  );
4517
4652
  }
4518
- validateValue(pointer3, value) {
4653
+ validateValue(pointer4, value) {
4519
4654
  }
4520
- setInitialValue(val12) {
4521
- this.validateValue(this.propsP, val12);
4522
- this._initialValue.set(val12);
4655
+ setInitialValue(val15) {
4656
+ this.validateValue(this.propsP, val15);
4657
+ this._initialValue.set(val15);
4523
4658
  }
4524
4659
  setSessionOverride(path, value) {
4525
4660
  const propConfig = getPropConfigByPath(this.template.staticConfig, path);
@@ -4539,8 +4674,8 @@ var SheetObject = class {
4539
4674
  * Internal: called by `RemoteSync` when a value update for this object
4540
4675
  * arrives from a remote editor window. Not exposed on the public API.
4541
4676
  */
4542
- setRemoteOverride(val12) {
4543
- this._remoteOverride.set(val12);
4677
+ setRemoteOverride(val15) {
4678
+ this._remoteOverride.set(val15);
4544
4679
  }
4545
4680
  /**
4546
4681
  * Internal: used by `RemoteSync` to subscribe to this object's fully
@@ -4549,7 +4684,7 @@ var SheetObject = class {
4549
4684
  */
4550
4685
  onFinalValueChange(fn2) {
4551
4686
  return onChange(
4552
- prism4(() => val4(this.getValues().getValue())),
4687
+ prism5(() => val5(this.getValues().getValue())),
4553
4688
  fn2
4554
4689
  );
4555
4690
  }
@@ -5120,9 +5255,9 @@ var SheetObjectTemplate = class {
5120
5255
  config,
5121
5256
  sheetTemplate.project
5122
5257
  );
5123
- this._config = new Atom4(configWithPrecisionDefaults);
5124
- this._temp_actions_atom = new Atom4(_temp_actions);
5125
- this.showPropsOf_atom = new Atom4([]);
5258
+ this._config = new Atom5(configWithPrecisionDefaults);
5259
+ this._temp_actions_atom = new Atom5(_temp_actions);
5260
+ this.showPropsOf_atom = new Atom5([]);
5126
5261
  this._transientPropPaths = normalizeTransientPropPaths(
5127
5262
  transient,
5128
5263
  config,
@@ -5179,7 +5314,7 @@ var SheetObjectTemplate = class {
5179
5314
  return this.showPropsOf_atom.pointer;
5180
5315
  }
5181
5316
  _stripNonPersistingPropsFromAhistoricState() {
5182
- const config = val5(this.configPointer);
5317
+ const config = val6(this.configPointer);
5183
5318
  this.project._stripNonPersistingPropsFromAhistoric(
5184
5319
  this.address.sheetId,
5185
5320
  this.address.objectKey,
@@ -5308,8 +5443,8 @@ var SheetObjectTemplate = class {
5308
5443
  getDefaultValues() {
5309
5444
  return this._cache.get(
5310
5445
  "getDefaultValues()",
5311
- () => prism5(() => {
5312
- const config = val5(this.configPointer);
5446
+ () => prism6(() => {
5447
+ const config = val6(this.configPointer);
5313
5448
  return getPropDefaultsOfSheetObject(config);
5314
5449
  })
5315
5450
  );
@@ -5321,14 +5456,14 @@ var SheetObjectTemplate = class {
5321
5456
  getStaticValues(sequenceVariant = DEFAULT_SEQUENCE_VARIANT) {
5322
5457
  return this._cache.get(
5323
5458
  "getStaticValues:".concat(sequenceVariant),
5324
- () => prism5(() => {
5325
- const sheetState = val5(this.pointerToSheetState);
5459
+ () => prism6(() => {
5460
+ const sheetState = val6(this.pointerToSheetState);
5326
5461
  const json = getEffectiveStaticOverrideForObject(
5327
5462
  sheetState,
5328
5463
  sequenceVariant,
5329
5464
  this.address.objectKey
5330
5465
  ) ?? {};
5331
- const config = val5(this.configPointer);
5466
+ const config = val6(this.configPointer);
5332
5467
  const deserialized = config.deserializeAndSanitize(json) || {};
5333
5468
  const withoutNonPersisting = stripNonPersistingPropValuesFromMap(
5334
5469
  deserialized,
@@ -5351,9 +5486,9 @@ var SheetObjectTemplate = class {
5351
5486
  getAhistoricStaticValues() {
5352
5487
  return this._cache.get(
5353
5488
  "getAhistoricStaticValues",
5354
- () => prism5(() => {
5355
- const json = val5(this.pointerToAhistoricStaticOverrides) ?? {};
5356
- const config = val5(this.configPointer);
5489
+ () => prism6(() => {
5490
+ const json = val6(this.pointerToAhistoricStaticOverrides) ?? {};
5491
+ const config = val6(this.configPointer);
5357
5492
  const deserialized = config.deserializeAndSanitize(json) || {};
5358
5493
  return stripNonPersistingPropValuesFromMap(deserialized, config);
5359
5494
  })
@@ -5368,13 +5503,13 @@ var SheetObjectTemplate = class {
5368
5503
  getArrayOfValidSequenceTracks(sequenceVariant) {
5369
5504
  return this._cache.get(
5370
5505
  "getArrayOfValidSequenceTracks:".concat(sequenceVariant),
5371
- () => prism5(
5506
+ () => prism6(
5372
5507
  () => {
5373
5508
  const effectiveSequenceVariant = isSheetPropsObjectKey(
5374
5509
  this.address.objectKey
5375
5510
  ) ? DEFAULT_SEQUENCE_VARIANT : sequenceVariant;
5376
5511
  const pointerToSheetState = this.project.pointers.historic.sheetsById[this.address.sheetId];
5377
- val5(pointerToSheetState.variantObjectOverrides);
5512
+ val6(pointerToSheetState.variantObjectOverrides);
5378
5513
  const defaultTrackIdByPropPath = valTrackIdByPropPathForObject(
5379
5514
  pointerToSheetState,
5380
5515
  DEFAULT_SEQUENCE_VARIANT,
@@ -5400,7 +5535,7 @@ var SheetObjectTemplate = class {
5400
5535
  return emptyArray;
5401
5536
  }
5402
5537
  const arrayOfIds = [];
5403
- const objectConfig = val5(this.configPointer);
5538
+ const objectConfig = val6(this.configPointer);
5404
5539
  for (const [pathToPropInString, effectiveTrack] of Object.entries(
5405
5540
  mergedTrackMap
5406
5541
  )) {
@@ -5450,8 +5585,8 @@ var SheetObjectTemplate = class {
5450
5585
  getMapOfValidSequenceTracks_forStudio(sequenceVariant) {
5451
5586
  return this._cache.get(
5452
5587
  "getMapOfValidSequenceTracks_forStudio:".concat(sequenceVariant),
5453
- () => prism5(() => {
5454
- const arr = val5(this.getArrayOfValidSequenceTracks(sequenceVariant));
5588
+ () => prism6(() => {
5589
+ const arr = val6(this.getArrayOfValidSequenceTracks(sequenceVariant));
5455
5590
  let map = {};
5456
5591
  for (const { pathToProp, trackId } of arr) {
5457
5592
  set_default(map, pathToProp, trackId);
@@ -5471,9 +5606,9 @@ var SheetObjectTemplate = class {
5471
5606
  getStaticButNotSequencedOverrides(sequenceVariant) {
5472
5607
  return this._cache.get(
5473
5608
  "getStaticButNotSequencedOverrides:".concat(sequenceVariant),
5474
- () => prism5(() => {
5475
- const staticOverrides = val5(this.getStaticValues(sequenceVariant));
5476
- const arrayOfValidSequenceTracks = val5(
5609
+ () => prism6(() => {
5610
+ const staticOverrides = val6(this.getStaticValues(sequenceVariant));
5611
+ const arrayOfValidSequenceTracks = val6(
5477
5612
  this.getArrayOfValidSequenceTracks(sequenceVariant)
5478
5613
  );
5479
5614
  const staticButNotSequencedOverrides = cloneDeep_default(staticOverrides);
@@ -5498,8 +5633,8 @@ var SheetObjectTemplate = class {
5498
5633
  })
5499
5634
  );
5500
5635
  }
5501
- getDefaultsAtPointer(pointer3) {
5502
- const { path } = getPointerParts2(pointer3);
5636
+ getDefaultsAtPointer(pointer4) {
5637
+ const { path } = getPointerParts2(pointer4);
5503
5638
  const defaults = this.getDefaultValues().getValue();
5504
5639
  const defaultsAtPath = getDeep(defaults, path);
5505
5640
  return defaultsAtPath;
@@ -5520,243 +5655,77 @@ function parsePathToProp(pathToPropInString) {
5520
5655
  }
5521
5656
 
5522
5657
  // core/src/sheets/SheetTemplate.ts
5523
- import { Atom as Atom9 } from "@unseenco/theatre-dataverse";
5524
-
5525
- // shared/src/utils/didYouMean.ts
5526
- var import_propose = __toESM(require_propose());
5527
- function didYouMean(str, dictionary, prepend = "Did you mean ", append = "?") {
5528
- const p2 = (0, import_propose.default)(str, dictionary, {
5529
- threshold: 0.7
5530
- });
5531
- if (p2) {
5532
- return prepend + JSON.stringify(p2) + append;
5533
- } else {
5534
- return "";
5535
- }
5536
- }
5537
-
5538
- // core/src/sequences/Sequence.ts
5539
- import { getPointerParts as getPointerParts3 } from "@unseenco/theatre-dataverse";
5540
- import { Atom as Atom7 } from "@unseenco/theatre-dataverse";
5541
- import { pointer as pointer2 } from "@unseenco/theatre-dataverse";
5542
- import { prism as prism6, val as val6 } from "@unseenco/theatre-dataverse";
5543
-
5544
- // shared/src/utils/defer.ts
5545
- function defer() {
5546
- let resolve;
5547
- let reject;
5548
- const promise = new Promise((rs, rj) => {
5549
- resolve = (v2) => {
5550
- rs(v2);
5551
- deferred.status = "resolved";
5552
- };
5553
- reject = (v2) => {
5554
- rj(v2);
5555
- deferred.status = "rejected";
5556
- };
5557
- });
5558
- const deferred = {
5559
- resolve,
5560
- reject,
5561
- promise,
5562
- status: "pending"
5563
- };
5564
- return deferred;
5565
- }
5658
+ import { Atom as Atom12 } from "@unseenco/theatre-dataverse";
5566
5659
 
5567
- // shared/src/utils/noop.ts
5568
- var noop = () => {
5569
- };
5570
- var noop_default = noop;
5660
+ // core/src/sequences/LiteSequence.ts
5661
+ import { prism as prism7 } from "@unseenco/theatre-dataverse";
5571
5662
 
5572
- // core/src/sequences/playbackControllers/DefaultPlaybackController.ts
5573
- import { Atom as Atom5 } from "@unseenco/theatre-dataverse";
5574
- var DefaultPlaybackController = class {
5663
+ // core/src/sequences/TheatreSequenceLite.ts
5664
+ import { Atom as Atom6, pointer as pointer2 } from "@unseenco/theatre-dataverse";
5665
+ var LITE_DEFAULT_LENGTH = 10;
5666
+ var TheatreSequenceLite = class {
5575
5667
  constructor() {
5576
- __publicField(this, "_stopPlayCallback", noop_default);
5577
- __publicField(this, "_state", new Atom5({
5578
- position: 0,
5579
- playing: false
5668
+ __publicField(this, "type", "Theatre_Sequence_PublicAPI");
5669
+ __publicField(this, "_state", new Atom6({
5670
+ playing: false,
5671
+ length: LITE_DEFAULT_LENGTH,
5672
+ position: 0
5580
5673
  }));
5581
- __publicField(this, "statePointer");
5582
- this.statePointer = this._state.pointer;
5674
+ __publicField(this, "pointer", pointer2({ root: this._state.pointer, path: [] }));
5583
5675
  }
5584
- destroy() {
5676
+ play() {
5677
+ return Promise.resolve(true);
5585
5678
  }
5586
5679
  pause() {
5587
- this._stopPlayCallback();
5588
- this.playing = false;
5589
- this._stopPlayCallback = noop_default;
5590
5680
  }
5591
- gotoPosition(time) {
5592
- this._updatePositionInState(time);
5681
+ get position() {
5682
+ return 0;
5593
5683
  }
5594
- _updatePositionInState(time) {
5595
- this._state.setByPointer((p2) => p2.position, time);
5684
+ set position(_position) {
5596
5685
  }
5597
- getCurrentPosition() {
5598
- return this._state.get().position;
5686
+ __experimental_getKeyframes(_prop) {
5687
+ return [];
5599
5688
  }
5600
- get playing() {
5601
- return this._state.get().playing;
5689
+ __experimental_getGsapClips() {
5690
+ return [];
5602
5691
  }
5603
- set playing(playing) {
5604
- this._state.setByPointer((p2) => p2.playing, playing);
5692
+ __experimental_getGsapScrollTriggers() {
5693
+ return [];
5605
5694
  }
5606
- play(iterationCount, range, rate, direction, ticker) {
5607
- if (this.playing) {
5608
- this.pause();
5695
+ attachAudio(_args) {
5696
+ return Promise.reject(
5697
+ new Error(
5698
+ "sequence.attachAudio() is not available in @unseenco/theatre-core-lite"
5699
+ )
5700
+ );
5701
+ }
5702
+ };
5703
+
5704
+ // core/src/sequences/LiteSequence.ts
5705
+ var LiteSequence = class {
5706
+ constructor() {
5707
+ __publicField(this, "publicApi", new TheatreSequenceLite());
5708
+ __publicField(this, "positionPrism", prism7(() => 0));
5709
+ }
5710
+ pause() {
5711
+ }
5712
+ };
5713
+
5714
+ // shared/src/globalVariableNames.ts
5715
+ var studioBundle = "__TheatreJS_StudioBundle";
5716
+ var coreBundle = "__TheatreJS_CoreBundle";
5717
+ var notifications = "__TheatreJS_Notifications";
5718
+
5719
+ // shared/src/notify.ts
5720
+ var createHandler = (type) => (...args) => {
5721
+ switch (type) {
5722
+ case "success": {
5723
+ logger_default.debug(args.slice(0, 2).join("\n"));
5724
+ break;
5609
5725
  }
5610
- this.playing = true;
5611
- const iterationLength = range[1] - range[0];
5612
- {
5613
- const startPos = this.getCurrentPosition();
5614
- if (startPos < range[0] || startPos > range[1]) {
5615
- if (direction === "normal" || direction === "alternate") {
5616
- this._updatePositionInState(range[0]);
5617
- } else if (direction === "reverse" || direction === "alternateReverse") {
5618
- this._updatePositionInState(range[1]);
5619
- }
5620
- } else if (direction === "normal" || direction === "alternate") {
5621
- if (startPos === range[1]) {
5622
- this._updatePositionInState(range[0]);
5623
- }
5624
- } else {
5625
- if (startPos === range[0]) {
5626
- this._updatePositionInState(range[1]);
5627
- }
5628
- }
5629
- }
5630
- const deferred = defer();
5631
- const initialTickerTime = ticker.time;
5632
- const totalPlaybackLength = iterationLength * iterationCount;
5633
- let initialElapsedPos = this.getCurrentPosition() - range[0];
5634
- if (direction === "reverse" || direction === "alternateReverse") {
5635
- initialElapsedPos = range[1] - this.getCurrentPosition();
5636
- }
5637
- const tick = (currentTickerTime) => {
5638
- const elapsedTickerTime = Math.max(
5639
- currentTickerTime - initialTickerTime,
5640
- 0
5641
- );
5642
- const elapsedTickerTimeInSeconds = elapsedTickerTime / 1e3;
5643
- const elapsedPos = Math.min(
5644
- elapsedTickerTimeInSeconds * rate + initialElapsedPos,
5645
- totalPlaybackLength
5646
- );
5647
- if (elapsedPos !== totalPlaybackLength) {
5648
- const iterationNumber = Math.floor(elapsedPos / iterationLength);
5649
- let currentIterationPos = elapsedPos / iterationLength % 1 * iterationLength;
5650
- if (direction !== "normal") {
5651
- if (direction === "reverse") {
5652
- currentIterationPos = iterationLength - currentIterationPos;
5653
- } else {
5654
- const isCurrentIterationNumberEven = iterationNumber % 2 === 0;
5655
- if (direction === "alternate") {
5656
- if (!isCurrentIterationNumberEven) {
5657
- currentIterationPos = iterationLength - currentIterationPos;
5658
- }
5659
- } else {
5660
- if (isCurrentIterationNumberEven) {
5661
- currentIterationPos = iterationLength - currentIterationPos;
5662
- }
5663
- }
5664
- }
5665
- }
5666
- this._updatePositionInState(currentIterationPos + range[0]);
5667
- requestNextTick();
5668
- } else {
5669
- if (direction === "normal") {
5670
- this._updatePositionInState(range[1]);
5671
- } else if (direction === "reverse") {
5672
- this._updatePositionInState(range[0]);
5673
- } else {
5674
- const isLastIterationEven = (iterationCount - 1) % 2 === 0;
5675
- if (direction === "alternate") {
5676
- if (isLastIterationEven) {
5677
- this._updatePositionInState(range[1]);
5678
- } else {
5679
- this._updatePositionInState(range[0]);
5680
- }
5681
- } else {
5682
- if (isLastIterationEven) {
5683
- this._updatePositionInState(range[0]);
5684
- } else {
5685
- this._updatePositionInState(range[1]);
5686
- }
5687
- }
5688
- }
5689
- this.playing = false;
5690
- deferred.resolve(true);
5691
- }
5692
- };
5693
- this._stopPlayCallback = () => {
5694
- ticker.offThisOrNextTick(tick);
5695
- ticker.offNextTick(tick);
5696
- if (this.playing) deferred.resolve(false);
5697
- };
5698
- const requestNextTick = () => ticker.onNextTick(tick);
5699
- ticker.onThisOrNextTick(tick);
5700
- return deferred.promise;
5701
- }
5702
- playDynamicRange(rangeD, ticker) {
5703
- if (this.playing) {
5704
- this.pause();
5705
- }
5706
- this.playing = true;
5707
- const deferred = defer();
5708
- const untapFromRangeD = rangeD.keepHot();
5709
- void deferred.promise.then(untapFromRangeD, untapFromRangeD);
5710
- let lastTickerTime = ticker.time;
5711
- const tick = (currentTickerTime) => {
5712
- const elapsedSinceLastTick = Math.max(
5713
- currentTickerTime - lastTickerTime,
5714
- 0
5715
- );
5716
- lastTickerTime = currentTickerTime;
5717
- const elapsedSinceLastTickInSeconds = elapsedSinceLastTick / 1e3;
5718
- const lastPosition = this.getCurrentPosition();
5719
- const range = rangeD.getValue();
5720
- if (lastPosition < range[0] || lastPosition > range[1]) {
5721
- this.gotoPosition(range[0]);
5722
- } else {
5723
- let newPosition = lastPosition + elapsedSinceLastTickInSeconds;
5724
- if (newPosition > range[1]) {
5725
- newPosition = range[0] + (newPosition - range[1]);
5726
- }
5727
- this.gotoPosition(newPosition);
5728
- }
5729
- requestNextTick();
5730
- };
5731
- this._stopPlayCallback = () => {
5732
- ticker.offThisOrNextTick(tick);
5733
- ticker.offNextTick(tick);
5734
- deferred.resolve(false);
5735
- };
5736
- const requestNextTick = () => ticker.onNextTick(tick);
5737
- ticker.onThisOrNextTick(tick);
5738
- return deferred.promise;
5739
- }
5740
- };
5741
-
5742
- // core/src/sequences/playbackControllers/AudioPlaybackController.ts
5743
- import { Atom as Atom6 } from "@unseenco/theatre-dataverse";
5744
-
5745
- // shared/src/globalVariableNames.ts
5746
- var studioBundle = "__TheatreJS_StudioBundle";
5747
- var coreBundle = "__TheatreJS_CoreBundle";
5748
- var notifications = "__TheatreJS_Notifications";
5749
-
5750
- // shared/src/notify.ts
5751
- var createHandler = (type) => (...args) => {
5752
- switch (type) {
5753
- case "success": {
5754
- logger_default.debug(args.slice(0, 2).join("\n"));
5755
- break;
5756
- }
5757
- case "info": {
5758
- logger_default.debug(args.slice(0, 2).join("\n"));
5759
- break;
5726
+ case "info": {
5727
+ logger_default.debug(args.slice(0, 2).join("\n"));
5728
+ break;
5760
5729
  }
5761
5730
  case "warning": {
5762
5731
  logger_default.warn(args.slice(0, 2).join("\n"));
@@ -5791,153 +5760,435 @@ if (typeof window !== "undefined") {
5791
5760
  });
5792
5761
  }
5793
5762
 
5794
- // core/src/sequences/playbackControllers/AudioPlaybackController.ts
5795
- var AudioPlaybackController = class {
5796
- constructor(_decodedBuffer, _audioContext, _nodeDestination) {
5797
- this._decodedBuffer = _decodedBuffer;
5798
- this._audioContext = _audioContext;
5799
- this._nodeDestination = _nodeDestination;
5800
- __publicField(this, "_mainGain");
5801
- __publicField(this, "_state", new Atom6({
5802
- position: 0,
5803
- playing: false
5804
- }));
5805
- __publicField(this, "statePointer");
5806
- __publicField(this, "_stopPlayCallback", noop_default);
5807
- this.statePointer = this._state.pointer;
5808
- this._mainGain = this._audioContext.createGain();
5809
- this._mainGain.connect(this._nodeDestination);
5763
+ // shared/src/utils/slashedPaths.ts
5764
+ var normalizeSlashedPath = (p2) => p2.replace(/^[\s\/]*/, "").replace(/[\s\/]*$/, "").replace(/\s*\/\s*/g, " / ");
5765
+ var getValidationErrorsOfSlashedPath = (p2) => {
5766
+ if (typeof p2 !== "string") return "it is not a string. (it is a ".concat(typeof p2, ")");
5767
+ const components = p2.split(/\//);
5768
+ if (components.length === 0) return "it is empty.";
5769
+ for (let i2 = 0; i2 < components.length; i2++) {
5770
+ const component = components[i2].trim();
5771
+ if (component.length === 0) return "the component #".concat(i2 + 1, " is empty.");
5772
+ if (component.length > 64)
5773
+ return "the component '".concat(component, "' must have 64 characters or less.");
5810
5774
  }
5811
- playDynamicRange(rangeD, ticker) {
5812
- const deferred = defer();
5813
- if (this._playing) this.pause();
5814
- this._playing = true;
5815
- let stop = void 0;
5816
- const play = () => {
5817
- stop?.();
5818
- stop = this._loopInRange(rangeD.getValue(), ticker).stop;
5819
- };
5820
- const untapFromRangeD = rangeD.onStale(play);
5821
- play();
5822
- this._stopPlayCallback = () => {
5823
- stop?.();
5824
- untapFromRangeD();
5825
- deferred.resolve(false);
5826
- };
5827
- return deferred.promise;
5775
+ };
5776
+ function validateAndSanitiseSlashedPathOrThrow(unsanitisedPath, fnName) {
5777
+ const sanitisedPath = normalizeSlashedPath(unsanitisedPath);
5778
+ if (process.env.NODE_ENV !== "development") {
5779
+ return sanitisedPath;
5828
5780
  }
5829
- _loopInRange(range, ticker) {
5830
- const rate = 1;
5831
- let startPos = this.getCurrentPosition();
5832
- const iterationLength = range[1] - range[0];
5833
- if (startPos < range[0] || startPos > range[1]) {
5834
- this._updatePositionInState(range[0]);
5835
- } else if (startPos === range[1]) {
5836
- this._updatePositionInState(range[0]);
5837
- }
5838
- startPos = this.getCurrentPosition();
5839
- const currentSource = this._audioContext.createBufferSource();
5840
- currentSource.buffer = this._decodedBuffer;
5841
- currentSource.connect(this._mainGain);
5842
- currentSource.playbackRate.value = rate;
5843
- currentSource.loop = true;
5844
- currentSource.loopStart = range[0];
5845
- currentSource.loopEnd = range[1];
5846
- const initialTickerTime = ticker.time;
5847
- let initialElapsedPos = startPos - range[0];
5848
- currentSource.start(0, startPos);
5849
- const tick = (currentTickerTime) => {
5850
- const elapsedTickerTime = Math.max(
5851
- currentTickerTime - initialTickerTime,
5852
- 0
5853
- );
5854
- const elapsedTickerTimeInSeconds = elapsedTickerTime / 1e3;
5855
- const elapsedPos = elapsedTickerTimeInSeconds * rate + initialElapsedPos;
5856
- let currentIterationPos = elapsedPos / iterationLength % 1 * iterationLength;
5857
- this._updatePositionInState(currentIterationPos + range[0]);
5858
- requestNextTick();
5859
- };
5860
- const requestNextTick = () => ticker.onNextTick(tick);
5861
- ticker.onThisOrNextTick(tick);
5862
- const stop = () => {
5863
- currentSource.stop();
5864
- currentSource.disconnect();
5865
- ticker.offThisOrNextTick(tick);
5866
- ticker.offNextTick(tick);
5867
- };
5868
- return { stop };
5781
+ const validation = getValidationErrorsOfSlashedPath(sanitisedPath);
5782
+ if (validation) {
5783
+ throw new InvalidArgumentError(
5784
+ "The path in ".concat(fnName, "(").concat(typeof unsanitisedPath === "string" ? '"'.concat(unsanitisedPath, '"') : "", ") is invalid because ").concat(validation)
5785
+ );
5869
5786
  }
5870
- get _playing() {
5871
- return this._state.get().playing;
5787
+ if (unsanitisedPath !== sanitisedPath) {
5788
+ notify.warning(
5789
+ "Invalid path provided to object",
5790
+ "The path in `".concat(fnName, '("').concat(unsanitisedPath, '")` was sanitized to `"').concat(sanitisedPath, '"`.\n\n') + "Please replace the path with the sanitized one, otherwise it will likely break in the future.",
5791
+ [
5792
+ {
5793
+ url: "https://unseen-theatre.netlify.app/docs/guide/manual/objects#creating-objects",
5794
+ title: "Sheet Objects"
5795
+ },
5796
+ {
5797
+ url: "https://unseen-theatre.netlify.app/docs/api/theatre-core#sheet.object",
5798
+ title: "API"
5799
+ }
5800
+ ]
5801
+ );
5872
5802
  }
5873
- set _playing(playing) {
5874
- this._state.setByPointer((p2) => p2.playing, playing);
5803
+ return sanitisedPath;
5804
+ }
5805
+
5806
+ // shared/src/utils/outlineNamespaces.ts
5807
+ function parseOutlineNamespacePath(namespacePath, fnName) {
5808
+ return validateAndSanitiseSlashedPathOrThrow(namespacePath, fnName).split(
5809
+ /\s*\/\s*/g
5810
+ );
5811
+ }
5812
+
5813
+ // core/src/sheets/TheatreSheet.ts
5814
+ var import_fast_deep_equal2 = __toESM(require_fast_deep_equal());
5815
+ var TheatreSheet = class {
5816
+ get type() {
5817
+ return "Theatre_Sheet_PublicAPI";
5875
5818
  }
5876
- destroy() {
5819
+ /**
5820
+ * @internal
5821
+ */
5822
+ constructor(sheet) {
5823
+ setPrivateAPI(this, sheet);
5877
5824
  }
5878
- pause() {
5879
- this._stopPlayCallback();
5880
- this._playing = false;
5881
- this._stopPlayCallback = noop_default;
5825
+ object(key, config, opts) {
5826
+ const internal2 = privateAPI(this);
5827
+ const sanitizedPath = validateAndSanitiseSlashedPathOrThrow(
5828
+ key,
5829
+ "sheet.object"
5830
+ );
5831
+ if (isSheetPropsObjectKey(sanitizedPath)) {
5832
+ throw new InvalidArgumentError(
5833
+ 'The key "'.concat(sanitizedPath, '" is reserved for sheet-level props. Use sheet.props() instead of sheet.object().')
5834
+ );
5835
+ }
5836
+ const existingObject = internal2.getObject(sanitizedPath);
5837
+ const nativeObject = null;
5838
+ const actions = opts?.__actions__THIS_API_IS_UNSTABLE_AND_WILL_CHANGE_IN_THE_NEXT_VERSION;
5839
+ if (existingObject) {
5840
+ if (process.env.NODE_ENV !== "production") {
5841
+ const prevConfig = getUnsanitizedObjectProps(existingObject);
5842
+ if (prevConfig) {
5843
+ if (!(0, import_fast_deep_equal2.default)(config, prevConfig)) {
5844
+ if (opts?.reconfigure === true) {
5845
+ const sanitizedConfig = compound(config);
5846
+ existingObject.template.reconfigure(sanitizedConfig);
5847
+ if (opts.transient !== void 0) {
5848
+ existingObject.template.setTransientPropPaths(
5849
+ opts.transient,
5850
+ sanitizedConfig
5851
+ );
5852
+ }
5853
+ if (opts.static !== void 0) {
5854
+ existingObject.template.setStaticPropPaths(
5855
+ opts.static,
5856
+ sanitizedConfig
5857
+ );
5858
+ }
5859
+ if (opts.showPropsOf !== void 0) {
5860
+ existingObject.template.setShowPropsOf(
5861
+ resolveShowPropsOfSources(
5862
+ existingObject,
5863
+ opts.showPropsOf,
5864
+ "sheet.object(..., {showPropsOf})"
5865
+ )
5866
+ );
5867
+ }
5868
+ setUnsanitizedObjectProps(existingObject, config);
5869
+ return existingObject.publicApi;
5870
+ } else {
5871
+ throw new Error(
5872
+ 'You seem to have called sheet.object("'.concat(key, '", config) twice, with different values for `config`. ') + "This is disallowed because changing the config of an object on the fly would make it difficult to reason about.\n\n" + 'You can fix this by either re-using the existing object, or calling sheet.object("'.concat(key, '", config) with the same config.\n\n') + "If you mean to reconfigure the object's config, set `{reconfigure: true}` in sheet.object(\"".concat(key, '", config, {reconfigure: true})')
5873
+ );
5874
+ }
5875
+ }
5876
+ }
5877
+ }
5878
+ if (actions) {
5879
+ existingObject.template._temp_setActions(actions);
5880
+ }
5881
+ if (opts?.visible !== void 0) {
5882
+ existingObject.template.setVisibleInOutline(opts.visible);
5883
+ }
5884
+ if (opts?.transient !== void 0) {
5885
+ existingObject.template.setTransientPropPaths(
5886
+ opts.transient,
5887
+ existingObject.template.staticConfig
5888
+ );
5889
+ }
5890
+ if (opts?.static !== void 0) {
5891
+ existingObject.template.setStaticPropPaths(
5892
+ opts.static,
5893
+ existingObject.template.staticConfig
5894
+ );
5895
+ }
5896
+ if (opts?.showPropsOf !== void 0) {
5897
+ existingObject.template.setShowPropsOf(
5898
+ resolveShowPropsOfSources(
5899
+ existingObject,
5900
+ opts.showPropsOf,
5901
+ "sheet.object(..., {showPropsOf})"
5902
+ )
5903
+ );
5904
+ }
5905
+ return existingObject.publicApi;
5906
+ } else {
5907
+ const sanitizedConfig = compound(config);
5908
+ const object = internal2.createObject(
5909
+ sanitizedPath,
5910
+ nativeObject,
5911
+ sanitizedConfig,
5912
+ actions,
5913
+ opts?.visible,
5914
+ opts?.transient,
5915
+ opts?.static
5916
+ );
5917
+ if (process.env.NODE_ENV !== "production") {
5918
+ setUnsanitizedObjectProps(object, config);
5919
+ }
5920
+ if (opts?.showPropsOf !== void 0) {
5921
+ object.template.setShowPropsOf(
5922
+ resolveShowPropsOfSources(
5923
+ object,
5924
+ opts.showPropsOf,
5925
+ "sheet.object(..., {showPropsOf})"
5926
+ )
5927
+ );
5928
+ }
5929
+ return object.publicApi;
5930
+ }
5882
5931
  }
5883
- gotoPosition(time) {
5884
- this._updatePositionInState(time);
5932
+ props(config, opts) {
5933
+ const internal2 = privateAPI(this);
5934
+ const objectKey = SHEET_PROPS_OBJECT_KEY;
5935
+ const existingObject = internal2.getSheetPropsObject();
5936
+ const nativeObject = null;
5937
+ const actions = opts?.__actions__THIS_API_IS_UNSTABLE_AND_WILL_CHANGE_IN_THE_NEXT_VERSION;
5938
+ if (existingObject) {
5939
+ if (process.env.NODE_ENV !== "production") {
5940
+ const prevConfig = getUnsanitizedObjectProps(existingObject);
5941
+ if (prevConfig) {
5942
+ if (!(0, import_fast_deep_equal2.default)(config, prevConfig)) {
5943
+ if (opts?.reconfigure === true) {
5944
+ const sanitizedConfig2 = compound(config);
5945
+ existingObject.template.reconfigure(sanitizedConfig2);
5946
+ if (opts.transient !== void 0) {
5947
+ existingObject.template.setTransientPropPaths(
5948
+ opts.transient,
5949
+ sanitizedConfig2
5950
+ );
5951
+ }
5952
+ if (opts.static !== void 0) {
5953
+ existingObject.template.setStaticPropPaths(
5954
+ opts.static,
5955
+ sanitizedConfig2
5956
+ );
5957
+ }
5958
+ setUnsanitizedObjectProps(existingObject, config);
5959
+ return existingObject.publicApi;
5960
+ } else {
5961
+ throw new Error(
5962
+ "You seem to have called sheet.props(config) twice, with different values for `config`. Use the same config on repeat calls, or pass `{reconfigure: true}` to change the schema."
5963
+ );
5964
+ }
5965
+ }
5966
+ }
5967
+ }
5968
+ if (actions) {
5969
+ existingObject.template._temp_setActions(actions);
5970
+ }
5971
+ if (opts?.transient !== void 0) {
5972
+ existingObject.template.setTransientPropPaths(
5973
+ opts.transient,
5974
+ existingObject.template.staticConfig
5975
+ );
5976
+ }
5977
+ if (opts?.static !== void 0) {
5978
+ existingObject.template.setStaticPropPaths(
5979
+ opts.static,
5980
+ existingObject.template.staticConfig
5981
+ );
5982
+ }
5983
+ return existingObject.publicApi;
5984
+ }
5985
+ const sanitizedConfig = compound(config);
5986
+ const object = internal2.createObject(
5987
+ objectKey,
5988
+ nativeObject,
5989
+ sanitizedConfig,
5990
+ actions,
5991
+ false,
5992
+ opts?.transient,
5993
+ opts?.static
5994
+ );
5995
+ if (process.env.NODE_ENV !== "production") {
5996
+ setUnsanitizedObjectProps(object, config);
5997
+ }
5998
+ return object.publicApi;
5885
5999
  }
5886
- _updatePositionInState(time) {
5887
- this._state.reduce((s2) => ({ ...s2, position: time }));
6000
+ get sequence() {
6001
+ return privateAPI(this).getSequence().publicApi;
5888
6002
  }
5889
- getCurrentPosition() {
5890
- return this._state.get().position;
6003
+ declareSequenceVariants(variants) {
6004
+ privateAPI(this).template.declareSequenceVariants(variants);
5891
6005
  }
5892
- play(iterationCount, range, rate, direction, ticker) {
5893
- if (this._playing) {
5894
- this.pause();
5895
- }
5896
- this._playing = true;
5897
- let startPos = this.getCurrentPosition();
5898
- const iterationLength = range[1] - range[0];
5899
- if (direction !== "normal") {
6006
+ setActiveSequenceVariant(variant) {
6007
+ privateAPI(this).setActiveSequenceVariant(variant);
6008
+ }
6009
+ getActiveSequenceVariant() {
6010
+ return privateAPI(this).getActiveSequenceVariant();
6011
+ }
6012
+ getSequenceMode() {
6013
+ return privateAPI(this).getSequenceMode();
6014
+ }
6015
+ setSequenceMode(mode) {
6016
+ privateAPI(this).setSequenceMode(mode);
6017
+ }
6018
+ setPageScrollDriver(driver) {
6019
+ privateAPI(this).setPageScrollDriver(driver);
6020
+ }
6021
+ get project() {
6022
+ return privateAPI(this).project.publicApi;
6023
+ }
6024
+ get address() {
6025
+ return { ...privateAPI(this).address };
6026
+ }
6027
+ detachObject(key) {
6028
+ const internal2 = privateAPI(this);
6029
+ const sanitizedPath = validateAndSanitiseSlashedPathOrThrow(
6030
+ key,
6031
+ 'sheet.deleteObject("'.concat(key, '")')
6032
+ );
6033
+ if (isSheetPropsObjectKey(sanitizedPath)) {
5900
6034
  throw new InvalidArgumentError(
5901
- 'Audio-controlled sequences can only be played in the "normal" direction. ' + "'".concat(direction, "' given.")
6035
+ "Sheet props cannot be detached. They are removed when the sheet instance is unloaded."
5902
6036
  );
5903
6037
  }
5904
- if (startPos < range[0] || startPos > range[1]) {
5905
- this._updatePositionInState(range[0]);
5906
- } else if (startPos === range[1]) {
5907
- this._updatePositionInState(range[0]);
5908
- }
5909
- startPos = this.getCurrentPosition();
5910
- const deferred = defer();
5911
- const currentSource = this._audioContext.createBufferSource();
5912
- currentSource.buffer = this._decodedBuffer;
5913
- currentSource.connect(this._mainGain);
5914
- currentSource.playbackRate.value = rate;
5915
- if (iterationCount > 1e3) {
6038
+ const obj = internal2.getObject(sanitizedPath);
6039
+ if (!obj) {
5916
6040
  notify.warning(
5917
- "Can't play sequences with audio more than 1000 times",
5918
- "The sequence will still play, but only 1000 times. The `iterationCount: ".concat(iterationCount, "` provided to `sequence.play()`\nis too high for a sequence with audio.\n\nTo fix this, either set `iterationCount` to a lower value, or remove the audio from the sequence."),
5919
- [
5920
- {
5921
- url: "https://www.theatrejs.com/docs/latest/manual/audio",
5922
- title: "Using Audio"
5923
- },
5924
- {
5925
- url: "https://www.theatrejs.com/docs/latest/api/core#sequence.attachaudio",
5926
- title: "Audio API"
5927
- }
5928
- ]
6041
+ "Couldn't delete object \"".concat(sanitizedPath, '"'),
6042
+ 'There is no object with key "'.concat(sanitizedPath, '".\n\nTo fix this, make sure you are calling `sheet.deleteObject("').concat(sanitizedPath, '")` with the correct key.')
5929
6043
  );
5930
- iterationCount = 1e3;
6044
+ console.warn('Object key "'.concat(sanitizedPath, '" does not exist.'));
6045
+ return;
5931
6046
  }
5932
- if (iterationCount > 1) {
5933
- currentSource.loop = true;
5934
- currentSource.loopStart = range[0];
5935
- currentSource.loopEnd = range[1];
6047
+ internal2.deleteObject(sanitizedPath);
6048
+ }
6049
+ getObjects() {
6050
+ return privateAPI(this).getObjects().map((obj) => obj.publicApi);
6051
+ }
6052
+ unload() {
6053
+ privateAPI(this).unload();
6054
+ }
6055
+ declareOutlineNamespace(namespacePath, opts) {
6056
+ const internal2 = privateAPI(this);
6057
+ const parsedPath = parseOutlineNamespacePath(
6058
+ namespacePath,
6059
+ "sheet.declareOutlineNamespace"
6060
+ );
6061
+ internal2.template.setOutlineNamespaceConfig(parsedPath.join(" / "), {
6062
+ defaultCollapsed: opts?.collapsed
6063
+ });
6064
+ }
6065
+ setOutlineNamespaceCollapsed(namespacePath, collapsed) {
6066
+ const internal2 = privateAPI(this);
6067
+ const parsedPath = parseOutlineNamespacePath(
6068
+ namespacePath,
6069
+ "sheet.setOutlineNamespaceCollapsed"
6070
+ );
6071
+ internal2.template.setOutlineNamespaceConfig(parsedPath.join(" / "), {
6072
+ collapsed
6073
+ });
6074
+ }
6075
+ };
6076
+
6077
+ // core/src/sheets/Sheet.ts
6078
+ import { Atom as Atom11, prism as prism11, val as val11 } from "@unseenco/theatre-dataverse";
6079
+
6080
+ // shared/src/utils/didYouMean.ts
6081
+ var import_propose = __toESM(require_propose());
6082
+ function didYouMean(str, dictionary, prepend = "Did you mean ", append = "?") {
6083
+ const p2 = (0, import_propose.default)(str, dictionary, {
6084
+ threshold: 0.7
6085
+ });
6086
+ if (p2) {
6087
+ return prepend + JSON.stringify(p2) + append;
6088
+ } else {
6089
+ return "";
6090
+ }
6091
+ }
6092
+
6093
+ // core/src/sequences/Sequence.ts
6094
+ import { getPointerParts as getPointerParts3 } from "@unseenco/theatre-dataverse";
6095
+ import { Atom as Atom10 } from "@unseenco/theatre-dataverse";
6096
+ import { pointer as pointer3 } from "@unseenco/theatre-dataverse";
6097
+ import { prism as prism8, val as val7 } from "@unseenco/theatre-dataverse";
6098
+
6099
+ // shared/src/utils/defer.ts
6100
+ function defer() {
6101
+ let resolve;
6102
+ let reject;
6103
+ const promise = new Promise((rs, rj) => {
6104
+ resolve = (v2) => {
6105
+ rs(v2);
6106
+ deferred.status = "resolved";
6107
+ };
6108
+ reject = (v2) => {
6109
+ rj(v2);
6110
+ deferred.status = "rejected";
6111
+ };
6112
+ });
6113
+ const deferred = {
6114
+ resolve,
6115
+ reject,
6116
+ promise,
6117
+ status: "pending"
6118
+ };
6119
+ return deferred;
6120
+ }
6121
+
6122
+ // shared/src/utils/noop.ts
6123
+ var noop = () => {
6124
+ };
6125
+ var noop_default = noop;
6126
+
6127
+ // core/src/sequences/playbackControllers/DefaultPlaybackController.ts
6128
+ import { Atom as Atom7 } from "@unseenco/theatre-dataverse";
6129
+ var DefaultPlaybackController = class {
6130
+ constructor() {
6131
+ __publicField(this, "_stopPlayCallback", noop_default);
6132
+ __publicField(this, "_state", new Atom7({
6133
+ position: 0,
6134
+ playing: false
6135
+ }));
6136
+ __publicField(this, "statePointer");
6137
+ this.statePointer = this._state.pointer;
6138
+ }
6139
+ destroy() {
6140
+ }
6141
+ pause() {
6142
+ this._stopPlayCallback();
6143
+ this.playing = false;
6144
+ this._stopPlayCallback = noop_default;
6145
+ }
6146
+ gotoPosition(time) {
6147
+ this._updatePositionInState(time);
6148
+ }
6149
+ _updatePositionInState(time) {
6150
+ this._state.setByPointer((p2) => p2.position, time);
6151
+ }
6152
+ getCurrentPosition() {
6153
+ return this._state.get().position;
6154
+ }
6155
+ get playing() {
6156
+ return this._state.get().playing;
6157
+ }
6158
+ set playing(playing) {
6159
+ this._state.setByPointer((p2) => p2.playing, playing);
6160
+ }
6161
+ play(iterationCount, range, rate, direction, ticker) {
6162
+ if (this.playing) {
6163
+ this.pause();
6164
+ }
6165
+ this.playing = true;
6166
+ const iterationLength = range[1] - range[0];
6167
+ {
6168
+ const startPos = this.getCurrentPosition();
6169
+ if (startPos < range[0] || startPos > range[1]) {
6170
+ if (direction === "normal" || direction === "alternate") {
6171
+ this._updatePositionInState(range[0]);
6172
+ } else if (direction === "reverse" || direction === "alternateReverse") {
6173
+ this._updatePositionInState(range[1]);
6174
+ }
6175
+ } else if (direction === "normal" || direction === "alternate") {
6176
+ if (startPos === range[1]) {
6177
+ this._updatePositionInState(range[0]);
6178
+ }
6179
+ } else {
6180
+ if (startPos === range[0]) {
6181
+ this._updatePositionInState(range[1]);
6182
+ }
6183
+ }
5936
6184
  }
6185
+ const deferred = defer();
5937
6186
  const initialTickerTime = ticker.time;
5938
- let initialElapsedPos = startPos - range[0];
5939
6187
  const totalPlaybackLength = iterationLength * iterationCount;
5940
- currentSource.start(0, startPos, totalPlaybackLength - initialElapsedPos);
6188
+ let initialElapsedPos = this.getCurrentPosition() - range[0];
6189
+ if (direction === "reverse" || direction === "alternateReverse") {
6190
+ initialElapsedPos = range[1] - this.getCurrentPosition();
6191
+ }
5941
6192
  const tick = (currentTickerTime) => {
5942
6193
  const elapsedTickerTime = Math.max(
5943
6194
  currentTickerTime - initialTickerTime,
@@ -5949,25 +6200,93 @@ var AudioPlaybackController = class {
5949
6200
  totalPlaybackLength
5950
6201
  );
5951
6202
  if (elapsedPos !== totalPlaybackLength) {
6203
+ const iterationNumber = Math.floor(elapsedPos / iterationLength);
5952
6204
  let currentIterationPos = elapsedPos / iterationLength % 1 * iterationLength;
6205
+ if (direction !== "normal") {
6206
+ if (direction === "reverse") {
6207
+ currentIterationPos = iterationLength - currentIterationPos;
6208
+ } else {
6209
+ const isCurrentIterationNumberEven = iterationNumber % 2 === 0;
6210
+ if (direction === "alternate") {
6211
+ if (!isCurrentIterationNumberEven) {
6212
+ currentIterationPos = iterationLength - currentIterationPos;
6213
+ }
6214
+ } else {
6215
+ if (isCurrentIterationNumberEven) {
6216
+ currentIterationPos = iterationLength - currentIterationPos;
6217
+ }
6218
+ }
6219
+ }
6220
+ }
5953
6221
  this._updatePositionInState(currentIterationPos + range[0]);
5954
6222
  requestNextTick();
5955
6223
  } else {
5956
- this._updatePositionInState(range[1]);
5957
- this._playing = false;
5958
- cleanup();
6224
+ if (direction === "normal") {
6225
+ this._updatePositionInState(range[1]);
6226
+ } else if (direction === "reverse") {
6227
+ this._updatePositionInState(range[0]);
6228
+ } else {
6229
+ const isLastIterationEven = (iterationCount - 1) % 2 === 0;
6230
+ if (direction === "alternate") {
6231
+ if (isLastIterationEven) {
6232
+ this._updatePositionInState(range[1]);
6233
+ } else {
6234
+ this._updatePositionInState(range[0]);
6235
+ }
6236
+ } else {
6237
+ if (isLastIterationEven) {
6238
+ this._updatePositionInState(range[0]);
6239
+ } else {
6240
+ this._updatePositionInState(range[1]);
6241
+ }
6242
+ }
6243
+ }
6244
+ this.playing = false;
5959
6245
  deferred.resolve(true);
5960
6246
  }
5961
6247
  };
5962
- const cleanup = () => {
5963
- currentSource.stop();
5964
- currentSource.disconnect();
6248
+ this._stopPlayCallback = () => {
6249
+ ticker.offThisOrNextTick(tick);
6250
+ ticker.offNextTick(tick);
6251
+ if (this.playing) deferred.resolve(false);
6252
+ };
6253
+ const requestNextTick = () => ticker.onNextTick(tick);
6254
+ ticker.onThisOrNextTick(tick);
6255
+ return deferred.promise;
6256
+ }
6257
+ playDynamicRange(rangeD, ticker) {
6258
+ if (this.playing) {
6259
+ this.pause();
6260
+ }
6261
+ this.playing = true;
6262
+ const deferred = defer();
6263
+ const untapFromRangeD = rangeD.keepHot();
6264
+ void deferred.promise.then(untapFromRangeD, untapFromRangeD);
6265
+ let lastTickerTime = ticker.time;
6266
+ const tick = (currentTickerTime) => {
6267
+ const elapsedSinceLastTick = Math.max(
6268
+ currentTickerTime - lastTickerTime,
6269
+ 0
6270
+ );
6271
+ lastTickerTime = currentTickerTime;
6272
+ const elapsedSinceLastTickInSeconds = elapsedSinceLastTick / 1e3;
6273
+ const lastPosition = this.getCurrentPosition();
6274
+ const range = rangeD.getValue();
6275
+ if (lastPosition < range[0] || lastPosition > range[1]) {
6276
+ this.gotoPosition(range[0]);
6277
+ } else {
6278
+ let newPosition = lastPosition + elapsedSinceLastTickInSeconds;
6279
+ if (newPosition > range[1]) {
6280
+ newPosition = range[0] + (newPosition - range[1]);
6281
+ }
6282
+ this.gotoPosition(newPosition);
6283
+ }
6284
+ requestNextTick();
5965
6285
  };
5966
6286
  this._stopPlayCallback = () => {
5967
- cleanup();
5968
6287
  ticker.offThisOrNextTick(tick);
5969
6288
  ticker.offNextTick(tick);
5970
- if (this._playing) deferred.resolve(false);
6289
+ deferred.resolve(false);
5971
6290
  };
5972
6291
  const requestNextTick = () => ticker.onNextTick(tick);
5973
6292
  ticker.onThisOrNextTick(tick);
@@ -5975,81 +6294,190 @@ var AudioPlaybackController = class {
5975
6294
  }
5976
6295
  };
5977
6296
 
5978
- // core/src/rafDrivers.ts
5979
- import { Ticker } from "@unseenco/theatre-dataverse";
5980
- var lastDriverId = 0;
5981
- function createRafDriver(conf) {
5982
- const tick = (time) => {
5983
- ticker.tick(time);
5984
- };
5985
- const ticker = new Ticker({
5986
- onActive() {
5987
- conf?.start?.();
5988
- },
5989
- onDormant() {
5990
- conf?.stop?.();
5991
- }
5992
- });
5993
- const driverPublicApi = {
5994
- tick,
5995
- id: lastDriverId++,
5996
- name: conf?.name ?? "CustomRafDriver-".concat(lastDriverId),
5997
- type: "Theatre_RafDriver_PublicAPI"
5998
- };
5999
- const driverPrivateApi = {
6000
- type: "Theatre_RafDriver_PrivateAPI",
6001
- publicApi: driverPublicApi,
6002
- ticker,
6003
- start: conf?.start,
6004
- stop: conf?.stop
6005
- };
6006
- setPrivateAPI(driverPublicApi, driverPrivateApi);
6007
- return driverPublicApi;
6008
- }
6009
-
6010
- // core/src/coreTicker.ts
6011
- function createBasicRafDriver() {
6012
- let rafId = null;
6013
- const start = () => {
6014
- if (typeof window !== "undefined") {
6015
- const onAnimationFrame = (t2) => {
6016
- driver.tick(t2);
6017
- rafId = window.requestAnimationFrame(onAnimationFrame);
6018
- };
6019
- rafId = window.requestAnimationFrame(onAnimationFrame);
6020
- } else {
6021
- driver.tick(0);
6022
- setTimeout(() => driver.tick(1), 0);
6023
- }
6024
- };
6025
- const stop = () => {
6026
- if (typeof window !== "undefined") {
6027
- if (rafId !== null) {
6028
- window.cancelAnimationFrame(rafId);
6029
- }
6030
- } else {
6297
+ // core/src/sequences/playbackControllers/AudioPlaybackController.ts
6298
+ import { Atom as Atom8 } from "@unseenco/theatre-dataverse";
6299
+ var AudioPlaybackController = class {
6300
+ constructor(_decodedBuffer, _audioContext, _nodeDestination) {
6301
+ this._decodedBuffer = _decodedBuffer;
6302
+ this._audioContext = _audioContext;
6303
+ this._nodeDestination = _nodeDestination;
6304
+ __publicField(this, "_mainGain");
6305
+ __publicField(this, "_state", new Atom8({
6306
+ position: 0,
6307
+ playing: false
6308
+ }));
6309
+ __publicField(this, "statePointer");
6310
+ __publicField(this, "_stopPlayCallback", noop_default);
6311
+ this.statePointer = this._state.pointer;
6312
+ this._mainGain = this._audioContext.createGain();
6313
+ this._mainGain.connect(this._nodeDestination);
6314
+ }
6315
+ playDynamicRange(rangeD, ticker) {
6316
+ const deferred = defer();
6317
+ if (this._playing) this.pause();
6318
+ this._playing = true;
6319
+ let stop = void 0;
6320
+ const play = () => {
6321
+ stop?.();
6322
+ stop = this._loopInRange(rangeD.getValue(), ticker).stop;
6323
+ };
6324
+ const untapFromRangeD = rangeD.onStale(play);
6325
+ play();
6326
+ this._stopPlayCallback = () => {
6327
+ stop?.();
6328
+ untapFromRangeD();
6329
+ deferred.resolve(false);
6330
+ };
6331
+ return deferred.promise;
6332
+ }
6333
+ _loopInRange(range, ticker) {
6334
+ const rate = 1;
6335
+ let startPos = this.getCurrentPosition();
6336
+ const iterationLength = range[1] - range[0];
6337
+ if (startPos < range[0] || startPos > range[1]) {
6338
+ this._updatePositionInState(range[0]);
6339
+ } else if (startPos === range[1]) {
6340
+ this._updatePositionInState(range[0]);
6031
6341
  }
6032
- };
6033
- const driver = createRafDriver({ name: "DefaultCoreRafDriver", start, stop });
6034
- return driver;
6035
- }
6036
- var coreRafDriver;
6037
- function getCoreRafDriver() {
6038
- if (!coreRafDriver) {
6039
- setCoreRafDriver(createBasicRafDriver());
6342
+ startPos = this.getCurrentPosition();
6343
+ const currentSource = this._audioContext.createBufferSource();
6344
+ currentSource.buffer = this._decodedBuffer;
6345
+ currentSource.connect(this._mainGain);
6346
+ currentSource.playbackRate.value = rate;
6347
+ currentSource.loop = true;
6348
+ currentSource.loopStart = range[0];
6349
+ currentSource.loopEnd = range[1];
6350
+ const initialTickerTime = ticker.time;
6351
+ let initialElapsedPos = startPos - range[0];
6352
+ currentSource.start(0, startPos);
6353
+ const tick = (currentTickerTime) => {
6354
+ const elapsedTickerTime = Math.max(
6355
+ currentTickerTime - initialTickerTime,
6356
+ 0
6357
+ );
6358
+ const elapsedTickerTimeInSeconds = elapsedTickerTime / 1e3;
6359
+ const elapsedPos = elapsedTickerTimeInSeconds * rate + initialElapsedPos;
6360
+ let currentIterationPos = elapsedPos / iterationLength % 1 * iterationLength;
6361
+ this._updatePositionInState(currentIterationPos + range[0]);
6362
+ requestNextTick();
6363
+ };
6364
+ const requestNextTick = () => ticker.onNextTick(tick);
6365
+ ticker.onThisOrNextTick(tick);
6366
+ const stop = () => {
6367
+ currentSource.stop();
6368
+ currentSource.disconnect();
6369
+ ticker.offThisOrNextTick(tick);
6370
+ ticker.offNextTick(tick);
6371
+ };
6372
+ return { stop };
6040
6373
  }
6041
- return coreRafDriver;
6042
- }
6043
- function getCoreTicker() {
6044
- return getCoreRafDriver().ticker;
6045
- }
6046
- function setCoreRafDriver(driver) {
6047
- if (coreRafDriver) {
6048
- throw new Error("`setCoreRafDriver()` is already called.");
6374
+ get _playing() {
6375
+ return this._state.get().playing;
6049
6376
  }
6050
- const driverPrivateApi = privateAPI(driver);
6051
- coreRafDriver = driverPrivateApi;
6052
- }
6377
+ set _playing(playing) {
6378
+ this._state.setByPointer((p2) => p2.playing, playing);
6379
+ }
6380
+ destroy() {
6381
+ }
6382
+ pause() {
6383
+ this._stopPlayCallback();
6384
+ this._playing = false;
6385
+ this._stopPlayCallback = noop_default;
6386
+ }
6387
+ gotoPosition(time) {
6388
+ this._updatePositionInState(time);
6389
+ }
6390
+ _updatePositionInState(time) {
6391
+ this._state.reduce((s2) => ({ ...s2, position: time }));
6392
+ }
6393
+ getCurrentPosition() {
6394
+ return this._state.get().position;
6395
+ }
6396
+ play(iterationCount, range, rate, direction, ticker) {
6397
+ if (this._playing) {
6398
+ this.pause();
6399
+ }
6400
+ this._playing = true;
6401
+ let startPos = this.getCurrentPosition();
6402
+ const iterationLength = range[1] - range[0];
6403
+ if (direction !== "normal") {
6404
+ throw new InvalidArgumentError(
6405
+ 'Audio-controlled sequences can only be played in the "normal" direction. ' + "'".concat(direction, "' given.")
6406
+ );
6407
+ }
6408
+ if (startPos < range[0] || startPos > range[1]) {
6409
+ this._updatePositionInState(range[0]);
6410
+ } else if (startPos === range[1]) {
6411
+ this._updatePositionInState(range[0]);
6412
+ }
6413
+ startPos = this.getCurrentPosition();
6414
+ const deferred = defer();
6415
+ const currentSource = this._audioContext.createBufferSource();
6416
+ currentSource.buffer = this._decodedBuffer;
6417
+ currentSource.connect(this._mainGain);
6418
+ currentSource.playbackRate.value = rate;
6419
+ if (iterationCount > 1e3) {
6420
+ notify.warning(
6421
+ "Can't play sequences with audio more than 1000 times",
6422
+ "The sequence will still play, but only 1000 times. The `iterationCount: ".concat(iterationCount, "` provided to `sequence.play()`\nis too high for a sequence with audio.\n\nTo fix this, either set `iterationCount` to a lower value, or remove the audio from the sequence."),
6423
+ [
6424
+ {
6425
+ url: "https://unseen-theatre.netlify.app/docs/guide/manual/audio",
6426
+ title: "Using Audio"
6427
+ },
6428
+ {
6429
+ url: "https://unseen-theatre.netlify.app/docs/api/theatre-core#sequence.attachaudio",
6430
+ title: "Audio API"
6431
+ }
6432
+ ]
6433
+ );
6434
+ iterationCount = 1e3;
6435
+ }
6436
+ if (iterationCount > 1) {
6437
+ currentSource.loop = true;
6438
+ currentSource.loopStart = range[0];
6439
+ currentSource.loopEnd = range[1];
6440
+ }
6441
+ const initialTickerTime = ticker.time;
6442
+ let initialElapsedPos = startPos - range[0];
6443
+ const totalPlaybackLength = iterationLength * iterationCount;
6444
+ currentSource.start(0, startPos, totalPlaybackLength - initialElapsedPos);
6445
+ const tick = (currentTickerTime) => {
6446
+ const elapsedTickerTime = Math.max(
6447
+ currentTickerTime - initialTickerTime,
6448
+ 0
6449
+ );
6450
+ const elapsedTickerTimeInSeconds = elapsedTickerTime / 1e3;
6451
+ const elapsedPos = Math.min(
6452
+ elapsedTickerTimeInSeconds * rate + initialElapsedPos,
6453
+ totalPlaybackLength
6454
+ );
6455
+ if (elapsedPos !== totalPlaybackLength) {
6456
+ let currentIterationPos = elapsedPos / iterationLength % 1 * iterationLength;
6457
+ this._updatePositionInState(currentIterationPos + range[0]);
6458
+ requestNextTick();
6459
+ } else {
6460
+ this._updatePositionInState(range[1]);
6461
+ this._playing = false;
6462
+ cleanup();
6463
+ deferred.resolve(true);
6464
+ }
6465
+ };
6466
+ const cleanup = () => {
6467
+ currentSource.stop();
6468
+ currentSource.disconnect();
6469
+ };
6470
+ this._stopPlayCallback = () => {
6471
+ cleanup();
6472
+ ticker.offThisOrNextTick(tick);
6473
+ ticker.offNextTick(tick);
6474
+ if (this._playing) deferred.resolve(false);
6475
+ };
6476
+ const requestNextTick = () => ticker.onNextTick(tick);
6477
+ ticker.onThisOrNextTick(tick);
6478
+ return deferred.promise;
6479
+ }
6480
+ };
6053
6481
 
6054
6482
  // core/src/sequences/TheatreSequence.ts
6055
6483
  var TheatreSequence = class {
@@ -6074,7 +6502,7 @@ var TheatreSequence = class {
6074
6502
  "You seem to have called `sequence.play()` before the project has finished loading.\n\nThis would **not** a problem in production when using `@unseenco/theatre-core`, since Theatre.js loads instantly in core mode. However, when using `@unseenco/theatre-studio`, it takes a few milliseconds for it to load your project's state, before which your sequences cannot start playing.\n\nTo fix this, simply defer calling `sequence.play()` until after the project is loaded, like this:\n\n```\nproject.ready.then(() => {\n sequence.play()\n})\n```",
6075
6503
  [
6076
6504
  {
6077
- url: "https://www.theatrejs.com/docs/0.5/api/core#project.ready",
6505
+ url: "https://unseen-theatre.netlify.app/docs/api/theatre-core#project.ready",
6078
6506
  title: "Project.ready"
6079
6507
  }
6080
6508
  ]
@@ -6100,14 +6528,27 @@ var TheatreSequence = class {
6100
6528
  __experimental_getGsapClips() {
6101
6529
  return privateAPI(this).getGsapClips();
6102
6530
  }
6531
+ __experimental_getGsapScrollTriggers() {
6532
+ return privateAPI(this).getGsapScrollTriggers();
6533
+ }
6103
6534
  async attachAudio(args) {
6535
+ const priv = privateAPI(this);
6536
+ if (priv._sheet.getSequenceMode() === "page") {
6537
+ notify.warning(
6538
+ "Audio is not supported in page mode",
6539
+ "Sequence audio expects time in seconds. Use time mode for attachAudio(), or scrub scroll-driven animation without audio."
6540
+ );
6541
+ return Promise.reject(
6542
+ new Error("sequence.attachAudio() is not supported in page mode")
6543
+ );
6544
+ }
6104
6545
  const { audioContext, destinationNode, decodedBuffer, gainNode } = await resolveAudioBuffer(args);
6105
6546
  const playbackController = new AudioPlaybackController(
6106
6547
  decodedBuffer,
6107
6548
  audioContext,
6108
6549
  gainNode
6109
6550
  );
6110
- privateAPI(this).replacePlaybackController(playbackController);
6551
+ priv.replacePlaybackController(playbackController);
6111
6552
  return { audioContext, destinationNode, decodedBuffer, gainNode };
6112
6553
  }
6113
6554
  get pointer() {
@@ -6205,6 +6646,31 @@ async function resolveAudioBuffer(args) {
6205
6646
  };
6206
6647
  }
6207
6648
 
6649
+ // shared/src/gsap/gsapStudioRegistryRevision.ts
6650
+ import { Atom as Atom9 } from "@unseenco/theatre-dataverse";
6651
+ var revisionAtom = new Atom9(0);
6652
+ var gsapStudioRegistryRevisionPointer = revisionAtom.pointer;
6653
+
6654
+ // shared/src/gsap/scrollTriggerRegistry.ts
6655
+ var DEFAULT_SHEET_INSTANCE_ID = "default";
6656
+ var REGISTRY_KEY = "__unseenco_theatre_gsap_scrollTriggerRegistry__";
6657
+ function sheetAddressKey(address) {
6658
+ const sheetInstanceId = address.sheetInstanceId ?? DEFAULT_SHEET_INSTANCE_ID;
6659
+ return "".concat(address.projectId, "|").concat(address.sheetId, "|").concat(sheetInstanceId);
6660
+ }
6661
+ function getStore() {
6662
+ const g2 = globalThis;
6663
+ if (!g2[REGISTRY_KEY]) {
6664
+ g2[REGISTRY_KEY] = { bySheetAddress: /* @__PURE__ */ new Map() };
6665
+ }
6666
+ return g2[REGISTRY_KEY];
6667
+ }
6668
+ function listScrollTriggerEntriesForSheet(sheetKey) {
6669
+ const map = getStore().bySheetAddress.get(sheetKey);
6670
+ if (!map) return [];
6671
+ return [...map.values()].sort((a2, b2) => a2.layout.start - b2.layout.start);
6672
+ }
6673
+
6208
6674
  // shared/src/sequence/trackData.ts
6209
6675
  function isBasicKeyframedTrack(track) {
6210
6676
  return track.type === "BasicKeyframedTrack";
@@ -6247,7 +6713,7 @@ var Sequence = class {
6247
6713
  __publicField(this, "_positionD");
6248
6714
  __publicField(this, "_positionFormatterD");
6249
6715
  __publicField(this, "_playableRangeD");
6250
- __publicField(this, "pointer", pointer2({ root: this, path: [] }));
6716
+ __publicField(this, "pointer", pointer3({ root: this, path: [] }));
6251
6717
  __publicField(this, "$$isPointerToPrismProvider", true);
6252
6718
  __publicField(this, "_logger");
6253
6719
  __publicField(this, "closestGridPosition", (posInUnitSpace) => {
@@ -6260,32 +6726,35 @@ var Sequence = class {
6260
6726
  this._logger = _project._logger.named("Sheet", _sheet.address.sheetId).named("Instance", _sheet.address.sheetInstanceId).named("Variant", _sequenceVariant);
6261
6727
  this.address = { ...this._sheet.address, sequenceName: _sequenceVariant };
6262
6728
  this.publicApi = new TheatreSequence(this);
6263
- this._playbackControllerBox = new Atom7(
6729
+ this._playbackControllerBox = new Atom10(
6264
6730
  playbackController ?? new DefaultPlaybackController()
6265
6731
  );
6266
- this._prismOfStatePointer = prism6(
6732
+ this._prismOfStatePointer = prism8(
6267
6733
  () => this._playbackControllerBox.prism.getValue().statePointer
6268
6734
  );
6269
- this._positionD = prism6(() => {
6735
+ this._positionD = prism8(() => {
6270
6736
  const statePointer = this._prismOfStatePointer.getValue();
6271
- return val6(statePointer.position);
6737
+ return val7(statePointer.position);
6272
6738
  });
6273
- this._positionFormatterD = prism6(() => {
6274
- const subUnitsPerUnit = val6(this._subUnitsPerUnitD);
6739
+ this._positionFormatterD = prism8(() => {
6740
+ const subUnitsPerUnit = val7(this._subUnitsPerUnitD);
6741
+ if (this._sheet.getSequenceMode() === "page") {
6742
+ return new PercentBasedPositionFormatter(subUnitsPerUnit);
6743
+ }
6275
6744
  return new TimeBasedPositionFormatter(subUnitsPerUnit);
6276
6745
  });
6277
6746
  }
6278
- pointerToPrism(pointer3) {
6279
- const { path } = getPointerParts3(pointer3);
6747
+ pointerToPrism(pointer4) {
6748
+ const { path } = getPointerParts3(pointer4);
6280
6749
  if (path.length === 0) {
6281
- return prism6(() => ({
6282
- length: val6(this.pointer.length),
6283
- playing: val6(this.pointer.playing),
6284
- position: val6(this.pointer.position)
6750
+ return prism8(() => ({
6751
+ length: val7(this.pointer.length),
6752
+ playing: val7(this.pointer.playing),
6753
+ position: val7(this.pointer.position)
6285
6754
  }));
6286
6755
  }
6287
6756
  if (path.length > 1) {
6288
- return prism6(() => void 0);
6757
+ return prism8(() => void 0);
6289
6758
  }
6290
6759
  const [prop] = path;
6291
6760
  if (prop === "length") {
@@ -6293,11 +6762,11 @@ var Sequence = class {
6293
6762
  } else if (prop === "position") {
6294
6763
  return this._positionD;
6295
6764
  } else if (prop === "playing") {
6296
- return prism6(() => {
6297
- return val6(this._prismOfStatePointer.getValue().playing);
6765
+ return prism8(() => {
6766
+ return val7(this._prismOfStatePointer.getValue().playing);
6298
6767
  });
6299
6768
  } else {
6300
- return prism6(() => void 0);
6769
+ return prism8(() => void 0);
6301
6770
  }
6302
6771
  }
6303
6772
  /**
@@ -6312,7 +6781,7 @@ var Sequence = class {
6312
6781
  "Argument prop must be a pointer to a SheetObject property"
6313
6782
  );
6314
6783
  }
6315
- const sheetState = val6(
6784
+ const sheetState = val7(
6316
6785
  this._project.pointers.historic.sheetsById[this._sheet.address.sheetId]
6317
6786
  );
6318
6787
  const trackP = getSequenceStateFromSheet(sheetState, this._sequenceVariant)?.tracksByObject[root2.address.objectKey];
@@ -6335,7 +6804,7 @@ var Sequence = class {
6335
6804
  * @internal Used by the public sequence API.
6336
6805
  */
6337
6806
  getGsapClipsForObject(objectKey) {
6338
- const sheetState = val6(
6807
+ const sheetState = val7(
6339
6808
  this._project.pointers.historic.sheetsById[this._sheet.address.sheetId]
6340
6809
  );
6341
6810
  const tracksOfObject = getSequenceStateFromSheet(
@@ -6352,7 +6821,7 @@ var Sequence = class {
6352
6821
  return result.sort((a2, b2) => a2.clip.start - b2.clip.start);
6353
6822
  }
6354
6823
  getGsapClips() {
6355
- const sheetState = val6(
6824
+ const sheetState = val7(
6356
6825
  this._project.pointers.historic.sheetsById[this._sheet.address.sheetId]
6357
6826
  );
6358
6827
  const sequenceState = getSequenceStateFromSheet(
@@ -6377,6 +6846,21 @@ var Sequence = class {
6377
6846
  }
6378
6847
  return result.sort((a2, b2) => a2.clip.start - b2.clip.start);
6379
6848
  }
6849
+ getGsapScrollTriggers() {
6850
+ if (this._sheet.getSequenceMode() !== "page") {
6851
+ return [];
6852
+ }
6853
+ const key = sheetAddressKey(this._sheet.address);
6854
+ return listScrollTriggerEntriesForSheet(key).filter((entry) => entry.sheetObject != null).map((entry) => ({
6855
+ objectKey: entry.sheetObject.address.objectKey,
6856
+ scrollTriggerId: entry.id,
6857
+ label: entry.label,
6858
+ layout: entry.layout,
6859
+ kind: entry.kind,
6860
+ animationSpanSeconds: entry.animationSpanSeconds,
6861
+ timelineChildren: entry.timelineChildren
6862
+ }));
6863
+ }
6380
6864
  get positionFormatter() {
6381
6865
  return this._positionFormatterD.getValue();
6382
6866
  }
@@ -6425,11 +6909,11 @@ var Sequence = class {
6425
6909
  return this._lengthD.getValue();
6426
6910
  }
6427
6911
  get playing() {
6428
- return val6(this._playbackControllerBox.get().statePointer.playing);
6912
+ return val7(this._playbackControllerBox.get().statePointer.playing);
6429
6913
  }
6430
6914
  _makeRangeFromSequenceTemplate() {
6431
- return prism6(() => {
6432
- return [0, val6(this._lengthD)];
6915
+ return prism8(() => {
6916
+ return [0, val7(this._lengthD)];
6433
6917
  });
6434
6918
  }
6435
6919
  /**
@@ -6447,6 +6931,13 @@ var Sequence = class {
6447
6931
  return this._playbackControllerBox.get().playDynamicRange(rangeD, ticker);
6448
6932
  }
6449
6933
  async play(conf, ticker) {
6934
+ if (this._sheet.getSequenceMode() === "page") {
6935
+ notify.warning(
6936
+ "Playback is disabled in page mode",
6937
+ "The sequence is driven by page scroll. Scrub the playhead or scroll the page instead of calling sequence.play()."
6938
+ );
6939
+ return false;
6940
+ }
6450
6941
  const sequenceDuration = this.length;
6451
6942
  const range = conf && conf.range ? conf.range : [0, sequenceDuration];
6452
6943
  if (process.env.NODE_ENV !== "production") {
@@ -6479,11 +6970,11 @@ var Sequence = class {
6479
6970
  ), "s) is longer than the duration of the sequence (").concat(sequenceDuration, "s).\n\nTo fix this, either set `conf.range[1]` to be less the duration of the sequence, or adjust the sequence duration in the UI."),
6480
6971
  [
6481
6972
  {
6482
- url: "https://www.theatrejs.com/docs/latest/manual/sequences",
6973
+ url: "https://unseen-theatre.netlify.app/docs/guide/manual/sequences",
6483
6974
  title: "Sequences"
6484
6975
  },
6485
6976
  {
6486
- url: "https://www.theatrejs.com/docs/latest/manual/sequences",
6977
+ url: "https://unseen-theatre.netlify.app/docs/guide/manual/sequences",
6487
6978
  title: "Playback API"
6488
6979
  }
6489
6980
  ]
@@ -6637,324 +7128,479 @@ var TimeBasedPositionFormatter = class {
6637
7128
  return posInUnitSpace.toFixed(2) + "s";
6638
7129
  }
6639
7130
  };
6640
- var second = 1;
6641
- var minute = second * 60;
6642
- var hour = minute * 60;
6643
-
6644
- // shared/src/utils/slashedPaths.ts
6645
- var normalizeSlashedPath = (p2) => p2.replace(/^[\s\/]*/, "").replace(/[\s\/]*$/, "").replace(/\s*\/\s*/g, " / ");
6646
- var getValidationErrorsOfSlashedPath = (p2) => {
6647
- if (typeof p2 !== "string") return "it is not a string. (it is a ".concat(typeof p2, ")");
6648
- const components = p2.split(/\//);
6649
- if (components.length === 0) return "it is empty.";
6650
- for (let i2 = 0; i2 < components.length; i2++) {
6651
- const component = components[i2].trim();
6652
- if (component.length === 0) return "the component #".concat(i2 + 1, " is empty.");
6653
- if (component.length > 64)
6654
- return "the component '".concat(component, "' must have 64 characters or less.");
7131
+ var PercentBasedPositionFormatter = class {
7132
+ constructor(_subUnitsPerUnit) {
7133
+ this._subUnitsPerUnit = _subUnitsPerUnit;
6655
7134
  }
6656
- };
6657
- function validateAndSanitiseSlashedPathOrThrow(unsanitisedPath, fnName) {
6658
- const sanitisedPath = normalizeSlashedPath(unsanitisedPath);
6659
- if (process.env.NODE_ENV !== "development") {
6660
- return sanitisedPath;
7135
+ formatSubUnitForGrid(posInUnitSpace) {
7136
+ const subUnitSize = 1 / this._subUnitsPerUnit;
7137
+ const withinUnit = posInUnitSpace % 1;
7138
+ const tenths = Math.round(withinUnit / subUnitSize);
7139
+ return tenths + "t";
6661
7140
  }
6662
- const validation = getValidationErrorsOfSlashedPath(sanitisedPath);
6663
- if (validation) {
6664
- throw new InvalidArgumentError(
6665
- "The path in ".concat(fnName, "(").concat(typeof unsanitisedPath === "string" ? '"'.concat(unsanitisedPath, '"') : "", ") is invalid because ").concat(validation)
6666
- );
7141
+ formatFullUnitForGrid(posInUnitSpace) {
7142
+ return Math.round(posInUnitSpace) + "%";
6667
7143
  }
6668
- if (unsanitisedPath !== sanitisedPath) {
6669
- notify.warning(
6670
- "Invalid path provided to object",
6671
- "The path in `".concat(fnName, '("').concat(unsanitisedPath, '")` was sanitized to `"').concat(sanitisedPath, '"`.\n\n') + "Please replace the path with the sanitized one, otherwise it will likely break in the future.",
6672
- [
6673
- {
6674
- url: "https://www.theatrejs.com/docs/latest/manual/objects#creating-sheet-objects",
6675
- title: "Sheet Objects"
6676
- },
6677
- {
6678
- url: "https://www.theatrejs.com/docs/latest/api/core#sheet.object",
6679
- title: "API"
6680
- }
6681
- ]
7144
+ formatForPlayhead(posInUnitSpace) {
7145
+ const whole = Math.floor(posInUnitSpace);
7146
+ const subUnitSize = 1 / this._subUnitsPerUnit;
7147
+ const withinUnit = posInUnitSpace - whole;
7148
+ const tenths = Math.round(withinUnit / subUnitSize);
7149
+ if (tenths <= 0) {
7150
+ return whole + "%";
7151
+ }
7152
+ return whole + "." + tenths + "%";
7153
+ }
7154
+ formatBasic(posInUnitSpace) {
7155
+ return posInUnitSpace.toFixed(1) + "%";
7156
+ }
7157
+ };
7158
+ var second = 1;
7159
+ var minute = second * 60;
7160
+ var hour = minute * 60;
7161
+
7162
+ // core/src/sheets/sheetGetSequenceFull.ts
7163
+ import { prism as prism9, val as val8 } from "@unseenco/theatre-dataverse";
7164
+
7165
+ // core/src/sheets/sheetSequenceMode.ts
7166
+ var PAGE_MODE_SEQUENCE_LENGTH = 100;
7167
+ var PAGE_MODE_SUB_UNITS_PER_UNIT = 10;
7168
+
7169
+ // core/src/sheets/sheetGetSequenceFull.ts
7170
+ var sanitizeSequenceLength = (len) => typeof len === "number" && isFinite(len) && len > 0 ? len : 10;
7171
+ var sanitizeSequenceSubUnitsPerUnit = (subs) => typeof subs === "number" && isInteger_default(subs) && subs > 0 ? subs : 30;
7172
+ function getOrCreateFullSequence(sheet, sequences, variantId) {
7173
+ if (!sequences[variantId]) {
7174
+ const lengthD = prism9(() => {
7175
+ if (val8(sheet.sequenceModeP) === "page") {
7176
+ return PAGE_MODE_SEQUENCE_LENGTH;
7177
+ }
7178
+ const sheetState = val8(
7179
+ sheet.project.pointers.historic.sheetsById[sheet.address.sheetId]
7180
+ );
7181
+ const unsanitized = getSequenceStateFromSheet(
7182
+ sheetState,
7183
+ variantId
7184
+ )?.length;
7185
+ return sanitizeSequenceLength(unsanitized);
7186
+ });
7187
+ const subUnitsPerUnitD = prism9(() => {
7188
+ if (val8(sheet.sequenceModeP) === "page") {
7189
+ return PAGE_MODE_SUB_UNITS_PER_UNIT;
7190
+ }
7191
+ const sheetState = val8(
7192
+ sheet.project.pointers.historic.sheetsById[sheet.address.sheetId]
7193
+ );
7194
+ const unsanitized = getSequenceStateFromSheet(
7195
+ sheetState,
7196
+ variantId
7197
+ )?.subUnitsPerUnit;
7198
+ return sanitizeSequenceSubUnitsPerUnit(unsanitized);
7199
+ });
7200
+ sequences[variantId] = new Sequence(
7201
+ sheet.template.project,
7202
+ sheet,
7203
+ lengthD,
7204
+ subUnitsPerUnitD,
7205
+ variantId
6682
7206
  );
6683
7207
  }
6684
- return sanitisedPath;
7208
+ return sequences[variantId];
6685
7209
  }
6686
7210
 
6687
- // shared/src/utils/outlineNamespaces.ts
6688
- function parseOutlineNamespacePath(namespacePath, fnName) {
6689
- return validateAndSanitiseSlashedPathOrThrow(namespacePath, fnName).split(
6690
- /\s*\/\s*/g
7211
+ // shared/src/gsap/applyTimelineChildTiming.ts
7212
+ function applyTimelineChildTimingToGsap(rootAnimation, timelineChildren, childById, onRebuild) {
7213
+ if (!timelineChildren.length) return true;
7214
+ let ok = applyTimelineChildTimingToGsapInner(
7215
+ rootAnimation,
7216
+ timelineChildren,
7217
+ childById
6691
7218
  );
6692
- }
6693
-
6694
- // core/src/sheets/TheatreSheet.ts
6695
- var import_fast_deep_equal2 = __toESM(require_fast_deep_equal());
6696
- var TheatreSheet = class {
6697
- get type() {
6698
- return "Theatre_Sheet_PublicAPI";
6699
- }
6700
- /**
6701
- * @internal
6702
- */
6703
- constructor(sheet) {
6704
- setPrivateAPI(this, sheet);
6705
- }
6706
- object(key, config, opts) {
6707
- const internal2 = privateAPI(this);
6708
- const sanitizedPath = validateAndSanitiseSlashedPathOrThrow(
6709
- key,
6710
- "sheet.object"
6711
- );
6712
- if (isSheetPropsObjectKey(sanitizedPath)) {
6713
- throw new InvalidArgumentError(
6714
- 'The key "'.concat(sanitizedPath, '" is reserved for sheet-level props. Use sheet.props() instead of sheet.object().')
7219
+ if (!ok && onRebuild) {
7220
+ const rebuilt = onRebuild();
7221
+ if (rebuilt) {
7222
+ ok = applyTimelineChildTimingToGsapInner(
7223
+ rebuilt,
7224
+ timelineChildren,
7225
+ childById
6715
7226
  );
6716
7227
  }
6717
- const existingObject = internal2.getObject(sanitizedPath);
6718
- const nativeObject = null;
6719
- const actions = opts?.__actions__THIS_API_IS_UNSTABLE_AND_WILL_CHANGE_IN_THE_NEXT_VERSION;
6720
- if (existingObject) {
6721
- if (process.env.NODE_ENV !== "production") {
6722
- const prevConfig = getUnsanitizedObjectProps(existingObject);
6723
- if (prevConfig) {
6724
- if (!(0, import_fast_deep_equal2.default)(config, prevConfig)) {
6725
- if (opts?.reconfigure === true) {
6726
- const sanitizedConfig = compound(config);
6727
- existingObject.template.reconfigure(sanitizedConfig);
6728
- if (opts.transient !== void 0) {
6729
- existingObject.template.setTransientPropPaths(
6730
- opts.transient,
6731
- sanitizedConfig
6732
- );
6733
- }
6734
- if (opts.static !== void 0) {
6735
- existingObject.template.setStaticPropPaths(
6736
- opts.static,
6737
- sanitizedConfig
6738
- );
6739
- }
6740
- if (opts.showPropsOf !== void 0) {
6741
- existingObject.template.setShowPropsOf(
6742
- resolveShowPropsOfSources(
6743
- existingObject,
6744
- opts.showPropsOf,
6745
- "sheet.object(..., {showPropsOf})"
6746
- )
6747
- );
6748
- }
6749
- setUnsanitizedObjectProps(existingObject, config);
6750
- return existingObject.publicApi;
6751
- } else {
6752
- throw new Error(
6753
- 'You seem to have called sheet.object("'.concat(key, '", config) twice, with different values for `config`. ') + "This is disallowed because changing the config of an object on the fly would make it difficult to reason about.\n\n" + 'You can fix this by either re-using the existing object, or calling sheet.object("'.concat(key, '", config) with the same config.\n\n') + "If you mean to reconfigure the object's config, set `{reconfigure: true}` in sheet.object(\"".concat(key, '", config, {reconfigure: true})')
6754
- );
6755
- }
6756
- }
6757
- }
6758
- }
6759
- if (actions) {
6760
- existingObject.template._temp_setActions(actions);
6761
- }
6762
- if (opts?.visible !== void 0) {
6763
- existingObject.template.setVisibleInOutline(opts.visible);
6764
- }
6765
- if (opts?.transient !== void 0) {
6766
- existingObject.template.setTransientPropPaths(
6767
- opts.transient,
6768
- existingObject.template.staticConfig
6769
- );
6770
- }
6771
- if (opts?.static !== void 0) {
6772
- existingObject.template.setStaticPropPaths(
6773
- opts.static,
6774
- existingObject.template.staticConfig
6775
- );
6776
- }
6777
- if (opts?.showPropsOf !== void 0) {
6778
- existingObject.template.setShowPropsOf(
6779
- resolveShowPropsOfSources(
6780
- existingObject,
6781
- opts.showPropsOf,
6782
- "sheet.object(..., {showPropsOf})"
6783
- )
6784
- );
6785
- }
6786
- return existingObject.publicApi;
6787
- } else {
6788
- const sanitizedConfig = compound(config);
6789
- const object = internal2.createObject(
6790
- sanitizedPath,
6791
- nativeObject,
6792
- sanitizedConfig,
6793
- actions,
6794
- opts?.visible,
6795
- opts?.transient,
6796
- opts?.static
6797
- );
6798
- if (process.env.NODE_ENV !== "production") {
6799
- setUnsanitizedObjectProps(object, config);
7228
+ }
7229
+ return ok;
7230
+ }
7231
+ function applyTimelineChildTimingToGsapInner(rootAnimation, timelineChildren, childById) {
7232
+ if (!childById || timelineChildren.length === 0) return true;
7233
+ let ok = true;
7234
+ for (const childState of timelineChildren) {
7235
+ const tween = childById.get(childState.childId);
7236
+ if (!tween) continue;
7237
+ try {
7238
+ const t2 = tween;
7239
+ if (typeof t2.startTime === "function") {
7240
+ t2.startTime(childState.localStart);
6800
7241
  }
6801
- if (opts?.showPropsOf !== void 0) {
6802
- object.template.setShowPropsOf(
6803
- resolveShowPropsOfSources(
6804
- object,
6805
- opts.showPropsOf,
6806
- "sheet.object(..., {showPropsOf})"
6807
- )
6808
- );
7242
+ if (typeof t2.duration === "function") {
7243
+ t2.duration(childState.localDuration);
6809
7244
  }
6810
- return object.publicApi;
7245
+ } catch {
7246
+ ok = false;
6811
7247
  }
6812
7248
  }
6813
- props(config, opts) {
6814
- const internal2 = privateAPI(this);
6815
- const objectKey = SHEET_PROPS_OBJECT_KEY;
6816
- const existingObject = internal2.getSheetPropsObject();
6817
- const nativeObject = null;
6818
- const actions = opts?.__actions__THIS_API_IS_UNSTABLE_AND_WILL_CHANGE_IN_THE_NEXT_VERSION;
6819
- if (existingObject) {
6820
- if (process.env.NODE_ENV !== "production") {
6821
- const prevConfig = getUnsanitizedObjectProps(existingObject);
6822
- if (prevConfig) {
6823
- if (!(0, import_fast_deep_equal2.default)(config, prevConfig)) {
6824
- if (opts?.reconfigure === true) {
6825
- const sanitizedConfig2 = compound(config);
6826
- existingObject.template.reconfigure(sanitizedConfig2);
6827
- if (opts.transient !== void 0) {
6828
- existingObject.template.setTransientPropPaths(
6829
- opts.transient,
6830
- sanitizedConfig2
6831
- );
6832
- }
6833
- if (opts.static !== void 0) {
6834
- existingObject.template.setStaticPropPaths(
6835
- opts.static,
6836
- sanitizedConfig2
6837
- );
6838
- }
6839
- setUnsanitizedObjectProps(existingObject, config);
6840
- return existingObject.publicApi;
6841
- } else {
6842
- throw new Error(
6843
- "You seem to have called sheet.props(config) twice, with different values for `config`. Use the same config on repeat calls, or pass `{reconfigure: true}` to change the schema."
6844
- );
6845
- }
6846
- }
6847
- }
6848
- }
6849
- if (actions) {
6850
- existingObject.template._temp_setActions(actions);
6851
- }
6852
- if (opts?.transient !== void 0) {
6853
- existingObject.template.setTransientPropPaths(
6854
- opts.transient,
6855
- existingObject.template.staticConfig
7249
+ return ok;
7250
+ }
7251
+
7252
+ // shared/src/gsap/syncGsapClipProgress.ts
7253
+ function getGsapAnimationTargetKey(animation, fallbackAnimationId) {
7254
+ const tween = animation;
7255
+ const targets = tween.targets?.();
7256
+ if (targets && targets.length > 0) {
7257
+ return targets[0];
7258
+ }
7259
+ return fallbackAnimationId;
7260
+ }
7261
+ function syncRegisteredGsapAnimationsForClips(sequencePosition, clips) {
7262
+ const enriched = [];
7263
+ for (const clip of clips) {
7264
+ const entry = getAnimationEntryBySheetAddressKey(
7265
+ clip.sheetObjectAddressKey,
7266
+ clip.gsapAnimationId
7267
+ );
7268
+ if (!entry?.animation) continue;
7269
+ enriched.push({
7270
+ ...clip,
7271
+ entry,
7272
+ targetKey: getGsapAnimationTargetKey(
7273
+ entry.animation,
7274
+ clip.gsapAnimationId
7275
+ )
7276
+ });
7277
+ }
7278
+ const byTarget = /* @__PURE__ */ new Map();
7279
+ for (const item of enriched) {
7280
+ const list = byTarget.get(item.targetKey) ?? [];
7281
+ list.push(item);
7282
+ byTarget.set(item.targetKey, list);
7283
+ }
7284
+ for (const group of byTarget.values()) {
7285
+ const sorted = [...group].sort((a2, b2) => a2.start - b2.start);
7286
+ for (const clip of sorted) {
7287
+ const progress = gsapClipSyncProgress(sequencePosition, clip);
7288
+ const entry = clip.entry;
7289
+ const animation = entry.animation;
7290
+ if (entry.kind === "timeline" && clip.timelineChildren && clip.timelineChildren.length > 0) {
7291
+ applyTimelineChildTimingToGsap(
7292
+ entry.animation,
7293
+ clip.timelineChildren,
7294
+ entry.timelineChildById,
7295
+ entry.onRebuildTimeline
6856
7296
  );
7297
+ const span = clip.timelineSpan ?? readGsapTweenTimelineDuration(entry.animation);
7298
+ const t2 = progress * Math.max(span, 0.01);
7299
+ if (typeof animation.time === "function") {
7300
+ animation.time(t2, true);
7301
+ } else {
7302
+ animation.progress?.(progress, true);
7303
+ }
7304
+ } else {
7305
+ animation.progress?.(progress, true);
6857
7306
  }
6858
- if (opts?.static !== void 0) {
6859
- existingObject.template.setStaticPropPaths(
6860
- opts.static,
6861
- existingObject.template.staticConfig
6862
- );
7307
+ }
7308
+ }
7309
+ }
7310
+ function readGsapTweenTimelineDuration(animation) {
7311
+ const tween = animation;
7312
+ const total = tween.totalDuration?.();
7313
+ if (typeof total === "number" && total > 0) return total;
7314
+ const d2 = tween.duration();
7315
+ return d2 > 0 ? d2 : 1;
7316
+ }
7317
+
7318
+ // shared/src/gsap/gsapAnimationRegistry.ts
7319
+ var DEFAULT_SHEET_INSTANCE_ID2 = "default";
7320
+ var REGISTRY_KEY2 = "__unseenco_theatre_gsap_animationRegistry__";
7321
+ function sheetObjectAddressKeyFromParts(address) {
7322
+ const sheetInstanceId = address.sheetInstanceId ?? DEFAULT_SHEET_INSTANCE_ID2;
7323
+ return "".concat(address.projectId, "|").concat(address.sheetId, "|").concat(sheetInstanceId, "|").concat(address.objectKey);
7324
+ }
7325
+ function getStore2() {
7326
+ const g2 = globalThis;
7327
+ if (!g2[REGISTRY_KEY2]) {
7328
+ g2[REGISTRY_KEY2] = {
7329
+ bySheetAddress: /* @__PURE__ */ new Map()
7330
+ };
7331
+ }
7332
+ return g2[REGISTRY_KEY2];
7333
+ }
7334
+ function getAnimationEntryBySheetAddressKey(sheetObjectAddressKey, animationId) {
7335
+ return getStore2().bySheetAddress.get(sheetObjectAddressKey)?.get(animationId);
7336
+ }
7337
+
7338
+ // shared/src/gsap/subscribeGsapClipSyncAtPlayhead.ts
7339
+ import { pointerToPrism, prism as prism10, val as val9 } from "@unseenco/theatre-dataverse";
7340
+
7341
+ // shared/src/gsap/syncGsapClipsAtSequencePosition.ts
7342
+ function syncGsapClipsAtSequencePosition(position, clips) {
7343
+ syncRegisteredGsapAnimationsForClips(
7344
+ position,
7345
+ clips
7346
+ );
7347
+ }
7348
+
7349
+ // shared/src/gsap/subscribeGsapClipSyncAtPlayhead.ts
7350
+ function subscribeGsapClipSyncAtPlayhead(source) {
7351
+ const positionPointer = source.pointer.position;
7352
+ const positionPrism = pointerToPrism(positionPointer);
7353
+ const clipsPrism = prism10(() => source.getGsapClipTimings());
7354
+ const syncNow = () => {
7355
+ const clips = clipsPrism.getValue();
7356
+ if (clips.length === 0) return;
7357
+ syncGsapClipsAtSequencePosition(val9(positionPointer), clips);
7358
+ };
7359
+ const untapPosition = positionPrism.onStale(syncNow);
7360
+ const untapClips = clipsPrism.onStale(syncNow);
7361
+ syncNow();
7362
+ return () => {
7363
+ untapPosition();
7364
+ untapClips();
7365
+ };
7366
+ }
7367
+
7368
+ // core/src/gsap/attachGsapSequenceBridge.ts
7369
+ function attachGsapSequenceBridge(sheet) {
7370
+ const sequence = sheet.sequence;
7371
+ const sheetAddress = privateAPI(sheet).address;
7372
+ return subscribeGsapClipSyncAtPlayhead({
7373
+ pointer: sequence.pointer,
7374
+ getGsapClipTimings: () => sequence.__experimental_getGsapClips().map(({ objectKey, clip }) => ({
7375
+ sheetObjectAddressKey: sheetObjectAddressKeyFromParts({
7376
+ projectId: sheetAddress.projectId,
7377
+ sheetId: sheetAddress.sheetId,
7378
+ sheetInstanceId: sheetAddress.sheetInstanceId,
7379
+ objectKey
7380
+ }),
7381
+ gsapAnimationId: clip.gsapAnimationId,
7382
+ start: clip.start,
7383
+ duration: clip.duration,
7384
+ timelineChildren: clip.timelineChildren,
7385
+ timelineSpan: clip.timelineSpan
7386
+ }))
7387
+ });
7388
+ }
7389
+
7390
+ // core/src/sheets/attachSheetScrollDriver.ts
7391
+ import { val as val10 } from "@unseenco/theatre-dataverse";
7392
+ var sheetScrollDrivers = /* @__PURE__ */ new WeakMap();
7393
+ var pageScrollDrivenSequencePositionListeners = /* @__PURE__ */ new Set();
7394
+ function onPageScrollDrivenSequencePosition(listener) {
7395
+ pageScrollDrivenSequencePositionListeners.add(listener);
7396
+ return () => {
7397
+ pageScrollDrivenSequencePositionListeners.delete(listener);
7398
+ };
7399
+ }
7400
+ function notifyPageScrollDrivenSequencePosition(sheet, position) {
7401
+ for (const listener of pageScrollDrivenSequencePositionListeners) {
7402
+ listener(sheet, position);
7403
+ }
7404
+ }
7405
+ function getSheetScrollDriver(sheet) {
7406
+ return sheetScrollDrivers.get(sheet);
7407
+ }
7408
+ function rememberSheetScrollDriver(sheet, driver) {
7409
+ sheetScrollDrivers.set(sheet, driver);
7410
+ }
7411
+ function progressFromScrollPosition(position, max) {
7412
+ if (max <= 0) return 0;
7413
+ if (position <= 0) return 0;
7414
+ if (position >= max - 1) return 1;
7415
+ return position / max;
7416
+ }
7417
+ function getNativeDocumentScrollingElement() {
7418
+ return document.scrollingElement ?? document.documentElement;
7419
+ }
7420
+ function addNativeDocumentScrollListener(handler) {
7421
+ document.addEventListener("scroll", handler, { passive: true, capture: true });
7422
+ return () => document.removeEventListener("scroll", handler, { capture: true });
7423
+ }
7424
+ function createScrollDriverFromElement(getMaxScroll, getScrollPos, setScrollPos, addScrollListener) {
7425
+ let suppressScrollEvents = false;
7426
+ let suppressGeneration = 0;
7427
+ const getProgress = () => {
7428
+ const max = getMaxScroll();
7429
+ return progressFromScrollPosition(getScrollPos(), max);
7430
+ };
7431
+ const setProgress = (progress) => {
7432
+ const max = getMaxScroll();
7433
+ const clamped = Math.max(0, Math.min(1, progress));
7434
+ const gen = ++suppressGeneration;
7435
+ suppressScrollEvents = true;
7436
+ setScrollPos(clamped * max);
7437
+ const release = () => {
7438
+ if (gen === suppressGeneration) {
7439
+ suppressScrollEvents = false;
6863
7440
  }
6864
- return existingObject.publicApi;
6865
- }
6866
- const sanitizedConfig = compound(config);
6867
- const object = internal2.createObject(
6868
- objectKey,
6869
- nativeObject,
6870
- sanitizedConfig,
6871
- actions,
6872
- false,
6873
- opts?.transient,
6874
- opts?.static
6875
- );
6876
- if (process.env.NODE_ENV !== "production") {
6877
- setUnsanitizedObjectProps(object, config);
7441
+ };
7442
+ requestAnimationFrame(() => requestAnimationFrame(release));
7443
+ };
7444
+ return {
7445
+ getProgress,
7446
+ setProgress,
7447
+ subscribe(onProgressChange) {
7448
+ let rafId = 0;
7449
+ const flush = () => {
7450
+ rafId = 0;
7451
+ if (suppressScrollEvents) return;
7452
+ onProgressChange(getProgress());
7453
+ };
7454
+ const scheduleFlush = () => {
7455
+ if (rafId !== 0) return;
7456
+ rafId = requestAnimationFrame(flush);
7457
+ };
7458
+ const handler = () => scheduleFlush();
7459
+ const removeScroll = addScrollListener(handler);
7460
+ const onResize = () => scheduleFlush();
7461
+ window.addEventListener("resize", onResize);
7462
+ return () => {
7463
+ removeScroll();
7464
+ window.removeEventListener("resize", onResize);
7465
+ if (rafId !== 0) cancelAnimationFrame(rafId);
7466
+ };
6878
7467
  }
6879
- return object.publicApi;
6880
- }
6881
- get sequence() {
6882
- return privateAPI(this).getSequence().publicApi;
6883
- }
6884
- declareSequenceVariants(variants) {
6885
- privateAPI(this).template.declareSequenceVariants(variants);
6886
- }
6887
- setActiveSequenceVariant(variant) {
6888
- privateAPI(this).setActiveSequenceVariant(variant);
6889
- }
6890
- getActiveSequenceVariant() {
6891
- return privateAPI(this).getActiveSequenceVariant();
6892
- }
6893
- get project() {
6894
- return privateAPI(this).project.publicApi;
6895
- }
6896
- get address() {
6897
- return { ...privateAPI(this).address };
6898
- }
6899
- detachObject(key) {
6900
- const internal2 = privateAPI(this);
6901
- const sanitizedPath = validateAndSanitiseSlashedPathOrThrow(
6902
- key,
6903
- 'sheet.deleteObject("'.concat(key, '")')
6904
- );
6905
- if (isSheetPropsObjectKey(sanitizedPath)) {
6906
- throw new InvalidArgumentError(
6907
- "Sheet props cannot be detached. They are removed when the sheet instance is unloaded."
6908
- );
7468
+ };
7469
+ }
7470
+ function createNativeDocumentScrollDriver() {
7471
+ const getMaxScroll = () => {
7472
+ const el = document.documentElement;
7473
+ return Math.max(0, el.scrollHeight - window.innerHeight);
7474
+ };
7475
+ return createScrollDriverFromElement(
7476
+ getMaxScroll,
7477
+ () => window.scrollY,
7478
+ (y2) => window.scrollTo({ top: y2, behavior: "instant" }),
7479
+ addNativeDocumentScrollListener
7480
+ );
7481
+ }
7482
+ function createNativeDocumentHorizontalScrollDriver() {
7483
+ const getMaxScroll = () => {
7484
+ const el = getNativeDocumentScrollingElement();
7485
+ return Math.max(0, el.scrollWidth - el.clientWidth);
7486
+ };
7487
+ const getScrollLeft = () => {
7488
+ const el = getNativeDocumentScrollingElement();
7489
+ return el.scrollLeft;
7490
+ };
7491
+ return createScrollDriverFromElement(
7492
+ getMaxScroll,
7493
+ getScrollLeft,
7494
+ (x2) => {
7495
+ getNativeDocumentScrollingElement().scrollLeft = x2;
7496
+ },
7497
+ addNativeDocumentScrollListener
7498
+ );
7499
+ }
7500
+ function createElementScrollDriver(element) {
7501
+ const getMaxScroll = () => Math.max(0, element.scrollHeight - element.clientHeight);
7502
+ return createScrollDriverFromElement(
7503
+ getMaxScroll,
7504
+ () => element.scrollTop,
7505
+ (y2) => {
7506
+ element.scrollTop = y2;
7507
+ },
7508
+ (handler) => {
7509
+ element.addEventListener("scroll", handler, { passive: true });
7510
+ return () => element.removeEventListener("scroll", handler);
6909
7511
  }
6910
- const obj = internal2.getObject(sanitizedPath);
6911
- if (!obj) {
6912
- notify.warning(
6913
- "Couldn't delete object \"".concat(sanitizedPath, '"'),
6914
- 'There is no object with key "'.concat(sanitizedPath, '".\n\nTo fix this, make sure you are calling `sheet.deleteObject("').concat(sanitizedPath, '")` with the correct key.')
6915
- );
6916
- console.warn('Object key "'.concat(sanitizedPath, '" does not exist.'));
6917
- return;
7512
+ );
7513
+ }
7514
+ function createElementHorizontalScrollDriver(element) {
7515
+ const getMaxScroll = () => Math.max(0, element.scrollWidth - element.clientWidth);
7516
+ return createScrollDriverFromElement(
7517
+ getMaxScroll,
7518
+ () => element.scrollLeft,
7519
+ (x2) => {
7520
+ element.scrollLeft = x2;
7521
+ },
7522
+ (handler) => {
7523
+ element.addEventListener("scroll", handler, { passive: true });
7524
+ return () => element.removeEventListener("scroll", handler);
6918
7525
  }
6919
- internal2.deleteObject(sanitizedPath);
6920
- }
6921
- getObjects() {
6922
- return privateAPI(this).getObjects().map((obj) => obj.publicApi);
6923
- }
6924
- unload() {
6925
- privateAPI(this).unload();
6926
- }
6927
- declareOutlineNamespace(namespacePath, opts) {
6928
- const internal2 = privateAPI(this);
6929
- const parsedPath = parseOutlineNamespacePath(
6930
- namespacePath,
6931
- "sheet.declareOutlineNamespace"
6932
- );
6933
- internal2.template.setOutlineNamespaceConfig(parsedPath.join(" / "), {
6934
- defaultCollapsed: opts?.collapsed
6935
- });
7526
+ );
7527
+ }
7528
+ function attachSheetScrollDriver(sheet, driver = createNativeDocumentScrollDriver()) {
7529
+ rememberSheetScrollDriver(sheet, driver);
7530
+ const sequence = sheet.sequence;
7531
+ const syncPositionFromScroll = (progress) => {
7532
+ const length = val10(sequence.pointer.length);
7533
+ if (length <= 0) return;
7534
+ sequence.position = progress * length;
7535
+ };
7536
+ const untapScroll = driver.subscribe((progress) => {
7537
+ syncPositionFromScroll(progress);
7538
+ notifyPageScrollDrivenSequencePosition(sheet, sequence.position);
7539
+ });
7540
+ syncPositionFromScroll(driver.getProgress());
7541
+ return () => {
7542
+ untapScroll();
7543
+ };
7544
+ }
7545
+ function pageScrollProgressFromSequence(sheet) {
7546
+ const length = val10(sheet.sequence.pointer.length);
7547
+ if (length <= 0) return 0;
7548
+ return sheet.sequence.position / length;
7549
+ }
7550
+ function setPageScrollProgress(sheet, progress) {
7551
+ const length = val10(sheet.sequence.pointer.length);
7552
+ if (length <= 0) return;
7553
+ const clamped = Math.max(0, Math.min(1, progress));
7554
+ sheet.sequence.position = clamped * length;
7555
+ }
7556
+ function syncPageScrollToSequencePosition(sheet, driver = getSheetScrollDriver(sheet) ?? createNativeDocumentScrollDriver()) {
7557
+ const progress = pageScrollProgressFromSequence(sheet);
7558
+ driver.setProgress(progress);
7559
+ }
7560
+ function syncNativeDocumentScrollToSequencePosition(sheet) {
7561
+ syncPageScrollToSequencePosition(sheet, createNativeDocumentScrollDriver());
7562
+ }
7563
+
7564
+ // core/src/sheets/sheetPageScrollAndGsapFull.ts
7565
+ function syncPageScrollDriverForSheet(host) {
7566
+ host._pageScrollDisposer?.();
7567
+ host._pageScrollDisposer = void 0;
7568
+ if (host.getSequenceMode() === "page") {
7569
+ const driver = host._customPageScrollDriver ?? createNativeDocumentScrollDriver();
7570
+ host._pageScrollDisposer = attachSheetScrollDriver(host.publicApi, driver);
6936
7571
  }
6937
- setOutlineNamespaceCollapsed(namespacePath, collapsed) {
6938
- const internal2 = privateAPI(this);
6939
- const parsedPath = parseOutlineNamespacePath(
6940
- namespacePath,
6941
- "sheet.setOutlineNamespaceCollapsed"
6942
- );
6943
- internal2.template.setOutlineNamespaceConfig(parsedPath.join(" / "), {
6944
- collapsed
6945
- });
7572
+ }
7573
+ function reattachGsapBridgeForSheet(host) {
7574
+ if (host._gsapBridgeDisposer) {
7575
+ host._gsapBridgeDisposer();
7576
+ host._gsapBridgeDisposer = attachGsapSequenceBridge(host.publicApi);
6946
7577
  }
6947
- };
7578
+ }
7579
+ function enableGsapSequenceBridgeForSheet(host) {
7580
+ if (host._gsapBridgeDisposer) return;
7581
+ host._gsapBridgeDisposer = attachGsapSequenceBridge(host.publicApi);
7582
+ syncPageScrollDriverForSheet(host);
7583
+ }
7584
+ function disposeRuntimeIntegrationsForSheet(host) {
7585
+ host._pageScrollDisposer?.();
7586
+ host._pageScrollDisposer = void 0;
7587
+ host._gsapBridgeDisposer?.();
7588
+ host._gsapBridgeDisposer = void 0;
7589
+ }
7590
+ function setPageScrollDriverForSheet(host, driver) {
7591
+ host._customPageScrollDriver = driver;
7592
+ syncPageScrollDriverForSheet(host);
7593
+ }
6948
7594
 
6949
7595
  // core/src/sheets/Sheet.ts
6950
- import { Atom as Atom8, prism as prism7, val as val7 } from "@unseenco/theatre-dataverse";
6951
7596
  var Sheet = class {
6952
7597
  constructor(template, instanceId) {
6953
7598
  this.template = template;
6954
7599
  this.instanceId = instanceId;
6955
- __publicField(this, "_objects", new Atom8({}));
7600
+ __publicField(this, "_objects", new Atom11({}));
6956
7601
  __publicField(this, "_sequences", {});
6957
- __publicField(this, "_activeSequenceVariant", new Atom8(
7602
+ __publicField(this, "_liteSequences", {});
7603
+ __publicField(this, "_activeSequenceVariant", new Atom11(
6958
7604
  DEFAULT_SEQUENCE_VARIANT
6959
7605
  ));
6960
7606
  /**
@@ -6962,7 +7608,15 @@ var Sheet = class {
6962
7608
  * value resolution (preview). User code can still update `_activeSequenceVariant`
6963
7609
  * via `setActiveSequenceVariant()` without affecting the Studio preview.
6964
7610
  */
6965
- __publicField(this, "_studioPreviewVariantOverride", new Atom8(void 0));
7611
+ __publicField(this, "_studioPreviewVariantOverride", new Atom11(void 0));
7612
+ __publicField(this, "_sequenceMode", new Atom11("time"));
7613
+ __publicField(this, "sequenceModeP", this._sequenceMode.pointer);
7614
+ /** @internal Used by full-runtime scroll/GSAP helpers (`sheetPageScrollAndGsapFull`). */
7615
+ __publicField(this, "_pageScrollDisposer");
7616
+ /** @internal */
7617
+ __publicField(this, "_customPageScrollDriver");
7618
+ /** @internal */
7619
+ __publicField(this, "_gsapBridgeDisposer");
6966
7620
  __publicField(this, "activeSequenceVariantP", this._activeSequenceVariant.pointer);
6967
7621
  __publicField(this, "effectiveActiveSequenceVariantD");
6968
7622
  __publicField(this, "address");
@@ -6979,12 +7633,12 @@ var Sheet = class {
6979
7633
  sheetInstanceId: this.instanceId
6980
7634
  };
6981
7635
  this.publicApi = new TheatreSheet(this);
6982
- this.effectiveActiveSequenceVariantD = prism7(() => {
6983
- const studioOverride = val7(this._studioPreviewVariantOverride.pointer);
7636
+ this.effectiveActiveSequenceVariantD = prism11(() => {
7637
+ const studioOverride = val11(this._studioPreviewVariantOverride.pointer);
6984
7638
  if (studioOverride !== void 0) {
6985
7639
  return studioOverride;
6986
7640
  }
6987
- return val7(this._activeSequenceVariant.pointer);
7641
+ return val11(this._activeSequenceVariant.pointer);
6988
7642
  });
6989
7643
  }
6990
7644
  /**
@@ -7035,8 +7689,11 @@ var Sheet = class {
7035
7689
  * this sheet instance from the project. Persisted state is kept.
7036
7690
  */
7037
7691
  unload() {
7038
- for (const sequence of Object.values(this._sequences)) {
7039
- sequence.pause();
7692
+ this.disposeRuntimeIntegrations();
7693
+ if (!isTheatreLiteMode()) {
7694
+ for (const sequence of Object.values(this._sequences)) {
7695
+ sequence.pause();
7696
+ }
7040
7697
  }
7041
7698
  for (const objectKey of Object.keys(
7042
7699
  this._objects.get()
@@ -7046,37 +7703,14 @@ var Sheet = class {
7046
7703
  this.project._unloadSheetInstance(this);
7047
7704
  }
7048
7705
  getSequence(variant) {
7049
- const variantId = variant ?? val7(this._activeSequenceVariant.pointer);
7050
- if (!this._sequences[variantId]) {
7051
- const lengthD = prism7(() => {
7052
- const sheetState = val7(
7053
- this.project.pointers.historic.sheetsById[this.address.sheetId]
7054
- );
7055
- const unsanitized = getSequenceStateFromSheet(
7056
- sheetState,
7057
- variantId
7058
- )?.length;
7059
- return sanitizeSequenceLength(unsanitized);
7060
- });
7061
- const subUnitsPerUnitD = prism7(() => {
7062
- const sheetState = val7(
7063
- this.project.pointers.historic.sheetsById[this.address.sheetId]
7064
- );
7065
- const unsanitized = getSequenceStateFromSheet(
7066
- sheetState,
7067
- variantId
7068
- )?.subUnitsPerUnit;
7069
- return sanitizeSequenceSubUnitsPerUnit(unsanitized);
7070
- });
7071
- this._sequences[variantId] = new Sequence(
7072
- this.template.project,
7073
- this,
7074
- lengthD,
7075
- subUnitsPerUnitD,
7076
- variantId
7077
- );
7706
+ const variantId = variant ?? val11(this._activeSequenceVariant.pointer);
7707
+ if (isTheatreLiteMode()) {
7708
+ if (!this._liteSequences[variantId]) {
7709
+ this._liteSequences[variantId] = new LiteSequence();
7710
+ }
7711
+ return this._liteSequences[variantId];
7078
7712
  }
7079
- return this._sequences[variantId];
7713
+ return getOrCreateFullSequence(this, this._sequences, variantId);
7080
7714
  }
7081
7715
  getActiveSequenceVariant() {
7082
7716
  return this._activeSequenceVariant.get();
@@ -7111,9 +7745,32 @@ var Sheet = class {
7111
7745
  }
7112
7746
  this._studioPreviewVariantOverride.set(variantId);
7113
7747
  }
7748
+ getSequenceMode() {
7749
+ return this._sequenceMode.get();
7750
+ }
7751
+ setSequenceMode(mode) {
7752
+ if (isTheatreLiteMode()) return;
7753
+ if (this._sequenceMode.get() === mode) return;
7754
+ this._sequenceMode.set(mode);
7755
+ syncPageScrollDriverForSheet(this);
7756
+ reattachGsapBridgeForSheet(this);
7757
+ }
7758
+ enableGsapSequenceBridge() {
7759
+ if (isTheatreLiteMode()) return;
7760
+ enableGsapSequenceBridgeForSheet(this);
7761
+ }
7762
+ disposeRuntimeIntegrations() {
7763
+ if (isTheatreLiteMode()) return;
7764
+ disposeRuntimeIntegrationsForSheet(this);
7765
+ }
7766
+ setPageScrollDriver(driver) {
7767
+ if (isTheatreLiteMode()) return;
7768
+ setPageScrollDriverForSheet(this, driver);
7769
+ }
7770
+ getPageScrollDriver() {
7771
+ return this._customPageScrollDriver;
7772
+ }
7114
7773
  };
7115
- var sanitizeSequenceLength = (len) => typeof len === "number" && isFinite(len) && len > 0 ? len : 10;
7116
- var sanitizeSequenceSubUnitsPerUnit = (subs) => typeof subs === "number" && isInteger_default(subs) && subs >= 1 && subs <= 1e3 ? subs : 30;
7117
7774
 
7118
7775
  // core/src/sheets/SheetTemplate.ts
7119
7776
  var SheetTemplate = class {
@@ -7121,13 +7778,13 @@ var SheetTemplate = class {
7121
7778
  this.project = project;
7122
7779
  __publicField(this, "type", "Theatre_SheetTemplate");
7123
7780
  __publicField(this, "address");
7124
- __publicField(this, "_instances", new Atom9({}));
7781
+ __publicField(this, "_instances", new Atom12({}));
7125
7782
  __publicField(this, "instancesP", this._instances.pointer);
7126
- __publicField(this, "_objectTemplates", new Atom9({}));
7783
+ __publicField(this, "_objectTemplates", new Atom12({}));
7127
7784
  __publicField(this, "objectTemplatesP", this._objectTemplates.pointer);
7128
7785
  __publicField(this, "_pendingOutlineNamespaces", {});
7129
7786
  __publicField(this, "_sequenceVariants", [DEFAULT_SEQUENCE_VARIANT]);
7130
- __publicField(this, "_visibleInOutline", new Atom9(true));
7787
+ __publicField(this, "_visibleInOutline", new Atom12(true));
7131
7788
  __publicField(this, "visibleInOutlineP", this._visibleInOutline.pointer);
7132
7789
  this.address = { ...project.address, sheetId };
7133
7790
  }
@@ -7210,7 +7867,7 @@ var SheetTemplate = class {
7210
7867
 
7211
7868
  // core/src/projects/Project.ts
7212
7869
  import { PointerProxy } from "@unseenco/theatre-dataverse";
7213
- import { Atom as Atom10 } from "@unseenco/theatre-dataverse";
7870
+ import { Atom as Atom13 } from "@unseenco/theatre-dataverse";
7214
7871
 
7215
7872
  // shared/src/utils/delay.ts
7216
7873
  var delay = (dur) => new Promise((resolve) => setTimeout(resolve, dur));
@@ -7648,8 +8305,165 @@ async function initialiseProjectState(studio, project, onDiskState) {
7648
8305
  });
7649
8306
  }
7650
8307
 
8308
+ // shared/src/sheets/pageScrollContext.ts
8309
+ var defaultPageScrollContext = {
8310
+ scroller: null,
8311
+ axis: "vertical"
8312
+ };
8313
+ var activePageScrollContext = defaultPageScrollContext;
8314
+ function setActivePageScrollContext(context) {
8315
+ activePageScrollContext = {
8316
+ scroller: context.scroller,
8317
+ axis: context.axis ?? "vertical"
8318
+ };
8319
+ }
8320
+ function getActivePageScrollContext() {
8321
+ return activePageScrollContext;
8322
+ }
8323
+ function resolvePageScrollAxis(context = defaultPageScrollContext) {
8324
+ return context.axis ?? "vertical";
8325
+ }
8326
+ function resolvePageScrollScroller(st, defaultsScroller) {
8327
+ const surface = st;
8328
+ const fromSt = surface.scroller ?? surface.vars?.scroller;
8329
+ if (fromSt != null) {
8330
+ return fromSt;
8331
+ }
8332
+ if (defaultsScroller !== void 0) {
8333
+ return defaultsScroller;
8334
+ }
8335
+ return null;
8336
+ }
8337
+ function isWindowLike(value) {
8338
+ return typeof Window !== "undefined" && (value === window || value instanceof Window);
8339
+ }
8340
+ function isNativeDocumentScroller(scroller) {
8341
+ if (scroller == null) return true;
8342
+ if (isWindowLike(scroller)) return true;
8343
+ if (typeof document === "undefined") return false;
8344
+ return scroller === document.documentElement || scroller === document.body;
8345
+ }
8346
+ function pageScrollScrollersMatch(a2, b2) {
8347
+ if (a2 === b2) return true;
8348
+ if (isNativeDocumentScroller(a2) && isNativeDocumentScroller(b2)) return true;
8349
+ return false;
8350
+ }
8351
+ function isScrollTriggerHorizontal(st) {
8352
+ const surface = st;
8353
+ return surface.horizontal === true || surface.vars?.horizontal === true;
8354
+ }
8355
+ function isPageScrollTrigger(st, context = defaultPageScrollContext) {
8356
+ const axis = resolvePageScrollAxis(context);
8357
+ const stHorizontal = isScrollTriggerHorizontal(st);
8358
+ if (stHorizontal !== (axis === "horizontal")) {
8359
+ return false;
8360
+ }
8361
+ const stScroller = resolvePageScrollScroller(st, context.scroller);
8362
+ return pageScrollScrollersMatch(stScroller, context.scroller);
8363
+ }
8364
+ function isVerticalPageScrollTrigger(st, context = defaultPageScrollContext) {
8365
+ return isPageScrollTrigger(st, {
8366
+ scroller: context.scroller,
8367
+ axis: "vertical"
8368
+ });
8369
+ }
8370
+
8371
+ // shared/src/gsap/scrollTriggerLayout.ts
8372
+ function getNativeDocumentMaxScroll(axis = "vertical") {
8373
+ if (typeof document === "undefined" || typeof window === "undefined") {
8374
+ return 0;
8375
+ }
8376
+ const el = document.documentElement;
8377
+ if (axis === "horizontal") {
8378
+ const scrolling = document.scrollingElement ?? el;
8379
+ return Math.max(0, scrolling.scrollWidth - scrolling.clientWidth);
8380
+ }
8381
+ return Math.max(0, el.scrollHeight - window.innerHeight);
8382
+ }
8383
+ function getMaxScrollForScroller(scroller, axis = "vertical") {
8384
+ if (typeof document === "undefined" || typeof window === "undefined") {
8385
+ return 0;
8386
+ }
8387
+ if (isNativeDocumentScroller(scroller)) {
8388
+ return getNativeDocumentMaxScroll(axis);
8389
+ }
8390
+ const el = scroller;
8391
+ if (axis === "horizontal") {
8392
+ return Math.max(0, el.scrollWidth - el.clientWidth);
8393
+ }
8394
+ return Math.max(0, el.scrollHeight - el.clientHeight);
8395
+ }
8396
+ function getMaxScrollForPageScrollContext(scroller, axis = "vertical") {
8397
+ return getMaxScrollForScroller(scroller, axis);
8398
+ }
8399
+
8400
+ // shared/src/gsap/domElementHighlightTarget.ts
8401
+ function resolveDomElementHighlightTarget(target) {
8402
+ if (typeof document === "undefined") {
8403
+ return null;
8404
+ }
8405
+ if (target.type === "id") {
8406
+ return document.getElementById(target.id);
8407
+ }
8408
+ try {
8409
+ const match = document.querySelector(target.selector);
8410
+ return match instanceof Element ? match : null;
8411
+ } catch {
8412
+ return null;
8413
+ }
8414
+ }
8415
+
8416
+ // shared/src/sheets/remoteDomElementHighlight.ts
8417
+ var listeners = /* @__PURE__ */ new Set();
8418
+ function setRemoteDomElementHighlight(element) {
8419
+ for (const listener of listeners) {
8420
+ listener(element);
8421
+ }
8422
+ }
8423
+
8424
+ // shared/src/sheets/remotePageScrollMetrics.ts
8425
+ var remoteMetrics;
8426
+ var listeners2 = /* @__PURE__ */ new Set();
8427
+ function setRemotePageScrollMetrics(metrics) {
8428
+ const prev = remoteMetrics;
8429
+ remoteMetrics = metrics;
8430
+ if (prev?.maxScroll !== metrics?.maxScroll || prev?.axis !== metrics?.axis) {
8431
+ for (const listener of listeners2) {
8432
+ listener();
8433
+ }
8434
+ }
8435
+ }
8436
+
7651
8437
  // core/src/internal/RemoteSync.ts
7652
- import { val as val8 } from "@unseenco/theatre-dataverse";
8438
+ import { pointerToPrism as pointerToPrism2, val as val12 } from "@unseenco/theatre-dataverse";
8439
+
8440
+ // core/src/internal/createDebouncedCallback.ts
8441
+ function createDebouncedCallback(fn2, delayMs) {
8442
+ let timeoutId;
8443
+ const clearPending = () => {
8444
+ if (timeoutId !== void 0) {
8445
+ clearTimeout(timeoutId);
8446
+ timeoutId = void 0;
8447
+ }
8448
+ };
8449
+ return {
8450
+ schedule() {
8451
+ clearPending();
8452
+ timeoutId = setTimeout(() => {
8453
+ timeoutId = void 0;
8454
+ fn2();
8455
+ }, delayMs);
8456
+ },
8457
+ flush() {
8458
+ if (timeoutId === void 0) return;
8459
+ clearPending();
8460
+ fn2();
8461
+ },
8462
+ cancel() {
8463
+ clearPending();
8464
+ }
8465
+ };
8466
+ }
7653
8467
 
7654
8468
  // core/src/internal/remoteEditor.ts
7655
8469
  function isRemoteEditorWindow() {
@@ -7657,6 +8471,10 @@ function isRemoteEditorWindow() {
7657
8471
  }
7658
8472
 
7659
8473
  // core/src/internal/RemoteSync.ts
8474
+ var REMOTE_HISTORIC_SYNC_DEBOUNCE_MS = 100;
8475
+ function shouldSyncPageScrollWhenApplyingTimelineUpdate(isEditor, sequenceMode) {
8476
+ return !isEditor && sequenceMode === "page";
8477
+ }
7660
8478
  var RemoteSync = class {
7661
8479
  constructor(project) {
7662
8480
  this.project = project;
@@ -7667,34 +8485,37 @@ var RemoteSync = class {
7667
8485
  __publicField(this, "objectUnsubs", /* @__PURE__ */ new Map());
7668
8486
  __publicField(this, "studio");
7669
8487
  __publicField(this, "activeSheet");
8488
+ __publicField(this, "historicSyncDebounce");
8489
+ __publicField(this, "lastBroadcastHistoricFingerprint");
8490
+ __publicField(this, "historicSyncUnsubs", []);
8491
+ __publicField(this, "remoteEditorActive", false);
8492
+ __publicField(this, "suppressTimelineBroadcast", false);
8493
+ __publicField(this, "listenerTimelineUnsub");
8494
+ __publicField(this, "listenerMetricsUnsubs", []);
8495
+ __publicField(this, "broadcastPageScrollMetrics");
7670
8496
  if (typeof BroadcastChannel === "undefined") return;
7671
8497
  this.channel = new BroadcastChannel(
7672
8498
  "theatre-remote:".concat(project.address.projectId)
7673
8499
  );
8500
+ this.channel.onmessage = (event) => {
8501
+ this._handleIncoming(event.data);
8502
+ };
7674
8503
  if (!this.isEditor) {
7675
- this.channel.onmessage = (event) => {
7676
- this._handleIncoming(event.data);
7677
- };
8504
+ this.listenerTimelineUnsub = onPageScrollDrivenSequencePosition(
8505
+ (sheet, position) => {
8506
+ this._broadcastTimelineFromListener(sheet, position);
8507
+ }
8508
+ );
7678
8509
  } else {
7679
8510
  const channel = this.channel;
7680
8511
  window.addEventListener("pagehide", () => {
7681
- const data = {};
7682
- if (this.studio) {
7683
- const projectId = this.project.address.projectId;
7684
- const historic = val8(
7685
- this.studio.atomP.historic.coreByProject[projectId]
7686
- );
7687
- const ahistoric = val8(
7688
- this.studio.atomP.ahistoric.coreByProject[projectId]
7689
- );
7690
- if (historic) {
7691
- data.historic = JSON.parse(JSON.stringify(historic));
7692
- if (ahistoric) {
7693
- data.ahistoric = JSON.parse(JSON.stringify(ahistoric));
7694
- }
7695
- }
8512
+ this.historicSyncDebounce?.flush();
8513
+ const data = this._readHistoricSnapshotFromStudio();
8514
+ if (data && this.lastBroadcastHistoricFingerprint === fingerprintHistoricSnapshot(data)) {
8515
+ channel.postMessage({ event: "disconnect", data: {} });
8516
+ return;
7696
8517
  }
7697
- channel.postMessage({ event: "disconnect", data });
8518
+ channel.postMessage({ event: "disconnect", data: data ?? {} });
7698
8519
  });
7699
8520
  }
7700
8521
  }
@@ -7745,8 +8566,13 @@ var RemoteSync = class {
7745
8566
  }
7746
8567
  attachStudio(studio) {
7747
8568
  this.studio = studio;
7748
- if (!this.isEditor || !this.channel) return;
8569
+ if (!this.channel) return;
8570
+ if (!this.isEditor) {
8571
+ this._attachListenerPageScrollMetricsBroadcast();
8572
+ return;
8573
+ }
7749
8574
  const channel = this.channel;
8575
+ channel.postMessage({ event: "editorHello", data: {} });
7750
8576
  const projectId = this.project.address.projectId;
7751
8577
  studio.publicApi.onSelectionChange((selection) => {
7752
8578
  for (const item of selection) {
@@ -7768,26 +8594,134 @@ var RemoteSync = class {
7768
8594
  }
7769
8595
  }
7770
8596
  });
7771
- let lastPosition;
7772
- const ticker = getCoreTicker();
7773
- const pollTimelinePosition = () => {
7774
- if (this.activeSheet) {
7775
- const position = this.activeSheet.publicApi.sequence.position;
7776
- if (position !== lastPosition) {
7777
- lastPosition = position;
7778
- const message = {
7779
- event: "updateTimeline",
7780
- data: { sheet: this.activeSheet.address.sheetId, position }
7781
- };
7782
- channel.postMessage(message);
7783
- }
7784
- }
7785
- ticker.onNextTick(pollTimelinePosition);
8597
+ let lastPosition;
8598
+ const ticker = getCoreTicker();
8599
+ const pollTimelinePosition = () => {
8600
+ if (this.activeSheet && !this.suppressTimelineBroadcast) {
8601
+ const position = this.activeSheet.publicApi.sequence.position;
8602
+ if (position !== lastPosition) {
8603
+ lastPosition = position;
8604
+ const message = {
8605
+ event: "updateTimeline",
8606
+ data: { sheet: this.activeSheet.address.sheetId, position }
8607
+ };
8608
+ channel.postMessage(message);
8609
+ }
8610
+ }
8611
+ ticker.onNextTick(pollTimelinePosition);
8612
+ };
8613
+ ticker.onNextTick(pollTimelinePosition);
8614
+ this.historicSyncDebounce = createDebouncedCallback(() => {
8615
+ this._broadcastHistoricSnapshot();
8616
+ }, REMOTE_HISTORIC_SYNC_DEBOUNCE_MS);
8617
+ const scheduleHistoricSync = () => {
8618
+ this.historicSyncDebounce?.schedule();
8619
+ };
8620
+ void studio.initialized.then(() => {
8621
+ this.historicSyncUnsubs.push(
8622
+ pointerToPrism2(studio.atomP.historic.coreByProject[projectId]).onChange(
8623
+ studio.ticker,
8624
+ scheduleHistoricSync,
8625
+ true
8626
+ ),
8627
+ pointerToPrism2(
8628
+ studio.atomP.ahistoric.coreByProject[projectId]
8629
+ ).onChange(studio.ticker, scheduleHistoricSync, true)
8630
+ );
8631
+ });
8632
+ }
8633
+ _readHistoricSnapshotFromStudio() {
8634
+ if (!this.studio) return void 0;
8635
+ const projectId = this.project.address.projectId;
8636
+ const historic = val12(
8637
+ this.studio.atomP.historic.coreByProject[projectId]
8638
+ );
8639
+ if (!historic) return void 0;
8640
+ const data = {
8641
+ historic: JSON.parse(JSON.stringify(historic))
8642
+ };
8643
+ const ahistoric = val12(
8644
+ this.studio.atomP.ahistoric.coreByProject[projectId]
8645
+ );
8646
+ if (ahistoric) {
8647
+ data.ahistoric = JSON.parse(JSON.stringify(ahistoric));
8648
+ }
8649
+ return data;
8650
+ }
8651
+ _broadcastHistoricSnapshot(options) {
8652
+ if (!this.channel) return;
8653
+ const data = this._readHistoricSnapshotFromStudio();
8654
+ if (!data) return;
8655
+ const fingerprint = fingerprintHistoricSnapshot(data);
8656
+ if (!options?.force && fingerprint === this.lastBroadcastHistoricFingerprint) {
8657
+ return;
8658
+ }
8659
+ this.lastBroadcastHistoricFingerprint = fingerprint;
8660
+ const message = { event: "updateHistoric", data };
8661
+ this.channel.postMessage(message);
8662
+ }
8663
+ _applyHistoricSnapshot(historic, ahistoric) {
8664
+ if (!this.studio) return;
8665
+ const projectId = this.project.address.projectId;
8666
+ this.studio.transaction(({ drafts }) => {
8667
+ drafts.historic.coreByProject[projectId] = historic;
8668
+ if (ahistoric) {
8669
+ drafts.ahistoric.coreByProject[projectId] = ahistoric;
8670
+ }
8671
+ drafts.ephemeral.coreByProject[projectId].loadingState = {
8672
+ type: "loaded"
8673
+ };
8674
+ });
8675
+ }
8676
+ _broadcastTimelineFromListener(sheet, position) {
8677
+ if (this.isEditor || !this.channel || !this.remoteEditorActive || this.suppressTimelineBroadcast) {
8678
+ return;
8679
+ }
8680
+ const registered = this.sheets.get(sheet.address.sheetId);
8681
+ if (!registered || registered.getSequenceMode() !== "page") return;
8682
+ const message = {
8683
+ event: "updateTimeline",
8684
+ data: { sheet: sheet.address.sheetId, position }
7786
8685
  };
7787
- ticker.onNextTick(pollTimelinePosition);
8686
+ this.channel.postMessage(message);
8687
+ }
8688
+ _postPageScrollMetrics() {
8689
+ if (!this.remoteEditorActive || !this.channel) return;
8690
+ const ctx = getActivePageScrollContext();
8691
+ const axis = resolvePageScrollAxis(ctx);
8692
+ const maxScroll = getMaxScrollForPageScrollContext(ctx.scroller, axis);
8693
+ const message = {
8694
+ event: "pageScrollMetrics",
8695
+ data: { maxScroll, axis }
8696
+ };
8697
+ this.channel.postMessage(message);
8698
+ }
8699
+ _attachListenerPageScrollMetricsBroadcast() {
8700
+ if (this.isEditor || !this.channel) return;
8701
+ const broadcast = () => this._postPageScrollMetrics();
8702
+ this.broadcastPageScrollMetrics = broadcast;
8703
+ const onScroll = () => broadcast();
8704
+ document.addEventListener("scroll", onScroll, { passive: true, capture: true });
8705
+ const onResize = () => broadcast();
8706
+ window.addEventListener("resize", onResize);
8707
+ const ScrollTrigger = globalThis.ScrollTrigger;
8708
+ ScrollTrigger?.addEventListener?.("refresh", broadcast);
8709
+ broadcast();
8710
+ this.listenerMetricsUnsubs.push(() => {
8711
+ document.removeEventListener("scroll", onScroll, { capture: true });
8712
+ window.removeEventListener("resize", onResize);
8713
+ ScrollTrigger?.removeEventListener?.("refresh", broadcast);
8714
+ });
7788
8715
  }
7789
8716
  _handleIncoming(msg) {
7790
8717
  switch (msg.event) {
8718
+ case "editorHello": {
8719
+ if (this.isEditor) break;
8720
+ this.remoteEditorActive = true;
8721
+ this.broadcastPageScrollMetrics?.();
8722
+ this._broadcastHistoricSnapshot({ force: true });
8723
+ break;
8724
+ }
7791
8725
  case "setSheet": {
7792
8726
  const sheet = this.sheets.get(msg.data.sheet);
7793
8727
  if (sheet && this.studio) {
@@ -7812,32 +8746,67 @@ var RemoteSync = class {
7812
8746
  const sheet = this.sheets.get(msg.data.sheet);
7813
8747
  if (sheet) {
7814
8748
  this.activeSheet = sheet;
8749
+ this.suppressTimelineBroadcast = true;
7815
8750
  sheet.publicApi.sequence.position = msg.data.position;
8751
+ if (shouldSyncPageScrollWhenApplyingTimelineUpdate(
8752
+ this.isEditor,
8753
+ sheet.getSequenceMode()
8754
+ )) {
8755
+ syncPageScrollToSequencePosition(sheet.publicApi);
8756
+ }
8757
+ requestAnimationFrame(() => {
8758
+ this.suppressTimelineBroadcast = false;
8759
+ });
8760
+ }
8761
+ break;
8762
+ }
8763
+ case "pageScrollMetrics": {
8764
+ if (!this.isEditor) break;
8765
+ const { maxScroll, axis } = msg.data;
8766
+ setRemotePageScrollMetrics({ maxScroll, axis });
8767
+ break;
8768
+ }
8769
+ case "highlightDomTarget": {
8770
+ if (this.isEditor || !this.remoteEditorActive) break;
8771
+ const target = msg.data.target;
8772
+ const element = resolveDomElementHighlightTarget(target);
8773
+ setRemoteDomElementHighlight(element);
8774
+ break;
8775
+ }
8776
+ case "clearDomHighlight": {
8777
+ if (this.isEditor || !this.remoteEditorActive) break;
8778
+ setRemoteDomElementHighlight(null);
8779
+ break;
8780
+ }
8781
+ case "updateHistoric": {
8782
+ const { historic, ahistoric } = msg.data;
8783
+ if (historic) {
8784
+ this._applyHistoricSnapshot(historic, ahistoric);
7816
8785
  }
7817
8786
  break;
7818
8787
  }
7819
8788
  case "disconnect": {
7820
8789
  const { historic, ahistoric } = msg.data;
7821
- if (historic && this.studio) {
7822
- const projectId = this.project.address.projectId;
7823
- this.studio.transaction(({ drafts }) => {
7824
- drafts.historic.coreByProject[projectId] = historic;
7825
- if (ahistoric) {
7826
- drafts.ahistoric.coreByProject[projectId] = ahistoric;
7827
- }
7828
- drafts.ephemeral.coreByProject[projectId].loadingState = {
7829
- type: "loaded"
7830
- };
7831
- });
8790
+ if (historic) {
8791
+ this._applyHistoricSnapshot(historic, ahistoric);
7832
8792
  }
7833
8793
  for (const obj of this.objects.values()) {
7834
8794
  obj.setRemoteOverride({});
7835
8795
  }
8796
+ if (!this.isEditor) {
8797
+ this.remoteEditorActive = false;
8798
+ setRemoteDomElementHighlight(null);
8799
+ } else {
8800
+ setRemotePageScrollMetrics(void 0);
8801
+ }
7836
8802
  break;
7837
8803
  }
7838
8804
  }
7839
8805
  }
7840
8806
  };
8807
+ function fingerprintHistoricSnapshot(data) {
8808
+ return JSON.stringify(data);
8809
+ }
7841
8810
 
7842
8811
  // core/src/_coreLogger.ts
7843
8812
  function noop2() {
@@ -7864,7 +8833,7 @@ function _coreLogger(config) {
7864
8833
  }
7865
8834
 
7866
8835
  // shared/src/utils/assets.ts
7867
- import { val as val9 } from "@unseenco/theatre-dataverse";
8836
+ import { val as val13 } from "@unseenco/theatre-dataverse";
7868
8837
 
7869
8838
  // shared/src/utils/forEachDeep.ts
7870
8839
  function forEachPropDeep(m, fn2, startingPath = []) {
@@ -7934,7 +8903,7 @@ var Project = class {
7934
8903
  __publicField(this, "_studioReadyDeferred");
7935
8904
  __publicField(this, "_assetStorageReadyDeferred");
7936
8905
  __publicField(this, "_readyPromise");
7937
- __publicField(this, "_sheetTemplates", new Atom10({}));
8906
+ __publicField(this, "_sheetTemplates", new Atom13({}));
7938
8907
  __publicField(this, "sheetTemplatesP", this._sheetTemplates.pointer);
7939
8908
  __publicField(this, "_studio");
7940
8909
  __publicField(this, "_onDiskStateAtom");
@@ -7947,7 +8916,7 @@ var Project = class {
7947
8916
  this._logger.traceDev("creating project");
7948
8917
  this.address = { projectId: id };
7949
8918
  this._remoteSync = new RemoteSync(this);
7950
- const onDiskStateAtom = new Atom10({
8919
+ const onDiskStateAtom = new Atom13({
7951
8920
  ahistoric: {
7952
8921
  ahistoricStuff: ""
7953
8922
  },
@@ -8002,14 +8971,14 @@ var Project = class {
8002
8971
  if (typeof window === "undefined") {
8003
8972
  if (process.env.NODE_ENV === "production") {
8004
8973
  console.error(
8005
- 'Argument config.state in Theatre.getProject("'.concat(id, '", config) is empty. ') + "You can safely ignore this message if you're developing a Next.js/Remix project in development mode. But if you are shipping to your end-users, then you need to set config.state, otherwise your project's state will be empty and nothing will animate. Learn more at https://www.theatrejs.com/docs/latest/manual/projects#state"
8974
+ 'Argument config.state in Theatre.getProject("'.concat(id, '", config) is empty. ') + "You can safely ignore this message if you're developing a Next.js/Remix project in development mode. But if you are shipping to your end-users, then you need to set config.state, otherwise your project's state will be empty and nothing will animate. Learn more at https://unseen-theatre.netlify.app/docs/guide/manual/projects#state"
8006
8975
  );
8007
8976
  }
8008
8977
  } else {
8009
8978
  setTimeout(() => {
8010
8979
  if (!this._studio) {
8011
8980
  throw new Error(
8012
- 'Argument config.state in Theatre.getProject("'.concat(id, '", config) is empty. This is fine ') + "while you are using @unseenco/theatre-core along with @unseenco/theatre-studio. But since @unseenco/theatre-studio " + 'is not loaded, the state of project "'.concat(id, '" will be empty.\n\n') + "To fix this, you need to add @unseenco/theatre-studio into the bundle and export the project's state. Learn how to do that at https://www.theatrejs.com/docs/latest/manual/projects#state\n"
8981
+ 'Argument config.state in Theatre.getProject("'.concat(id, '", config) is empty. This is fine ') + "while you are using @unseenco/theatre-core along with @unseenco/theatre-studio. But since @unseenco/theatre-studio " + 'is not loaded, the state of project "'.concat(id, '" will be empty.\n\n') + "To fix this, you need to add @unseenco/theatre-studio into the bundle and export the project's state. Learn how to do that at https://unseen-theatre.netlify.app/docs/guide/manual/projects#state\n"
8013
8982
  );
8014
8983
  }
8015
8984
  }, 1e3);
@@ -8073,6 +9042,7 @@ var Project = class {
8073
9042
  template.setVisibleInOutline(opts.visible);
8074
9043
  }
8075
9044
  const sheet = template.getInstance(instanceId);
9045
+ applySheetRuntimeOptions(sheet, opts);
8076
9046
  this._remoteSync.registerSheet(sheet);
8077
9047
  return sheet;
8078
9048
  }
@@ -8353,13 +9323,13 @@ var Project = class {
8353
9323
  };
8354
9324
 
8355
9325
  // shared/src/utils/sanitizers.ts
8356
- var _validateSym = (val12, thingy, range) => {
8357
- if (typeof val12 !== "string") {
8358
- return "".concat(thingy, " must be a string. ").concat(userReadableTypeOfValue_default(val12), " given.");
8359
- } else if (val12.trim().length !== val12.length) {
8360
- return "".concat(thingy, " must not have leading or trailing spaces. '").concat(val12, "' given.");
8361
- } else if (val12.length < range[0] || val12.length > range[1]) {
8362
- return "".concat(thingy, " must have between ").concat(range[0], " and ").concat(range[1], " characters. '").concat(val12, "' given.");
9326
+ var _validateSym = (val15, thingy, range) => {
9327
+ if (typeof val15 !== "string") {
9328
+ return "".concat(thingy, " must be a string. ").concat(userReadableTypeOfValue_default(val15), " given.");
9329
+ } else if (val15.trim().length !== val15.length) {
9330
+ return "".concat(thingy, " must not have leading or trailing spaces. '").concat(val15, "' given.");
9331
+ } else if (val15.length < range[0] || val15.length > range[1]) {
9332
+ return "".concat(thingy, " must have between ").concat(range[0], " and ").concat(range[1], " characters. '").concat(val15, "' given.");
8363
9333
  }
8364
9334
  };
8365
9335
  var validateName = (name, thingy, shouldThrow = false) => {
@@ -8473,196 +9443,10 @@ var TheatreProject = class {
8473
9443
  }
8474
9444
  };
8475
9445
 
8476
- // core/src/coreExports.ts
9446
+ // core/src/coreExportsShared.ts
8477
9447
  var import_fast_deep_equal3 = __toESM(require_fast_deep_equal());
8478
9448
  import { isPointer } from "@unseenco/theatre-dataverse";
8479
- import { isPrism, pointerToPrism as pointerToPrism2 } from "@unseenco/theatre-dataverse";
8480
-
8481
- // shared/src/gsap/applyTimelineChildTiming.ts
8482
- function applyTimelineChildTimingToGsap(rootAnimation, timelineChildren, childById, onRebuild) {
8483
- if (!timelineChildren.length) return true;
8484
- let ok = applyTimelineChildTimingToGsapInner(
8485
- rootAnimation,
8486
- timelineChildren,
8487
- childById
8488
- );
8489
- if (!ok && onRebuild) {
8490
- const rebuilt = onRebuild();
8491
- if (rebuilt) {
8492
- ok = applyTimelineChildTimingToGsapInner(
8493
- rebuilt,
8494
- timelineChildren,
8495
- childById
8496
- );
8497
- }
8498
- }
8499
- return ok;
8500
- }
8501
- function applyTimelineChildTimingToGsapInner(rootAnimation, timelineChildren, childById) {
8502
- if (!childById || timelineChildren.length === 0) return true;
8503
- let ok = true;
8504
- for (const childState of timelineChildren) {
8505
- const tween = childById.get(childState.childId);
8506
- if (!tween) continue;
8507
- try {
8508
- const t2 = tween;
8509
- if (typeof t2.startTime === "function") {
8510
- t2.startTime(childState.localStart);
8511
- }
8512
- if (typeof t2.duration === "function") {
8513
- t2.duration(childState.localDuration);
8514
- }
8515
- } catch {
8516
- ok = false;
8517
- }
8518
- }
8519
- return ok;
8520
- }
8521
-
8522
- // shared/src/gsap/syncGsapClipProgress.ts
8523
- function getGsapAnimationTargetKey(animation, fallbackAnimationId) {
8524
- const tween = animation;
8525
- const targets = tween.targets?.();
8526
- if (targets && targets.length > 0) {
8527
- return targets[0];
8528
- }
8529
- return fallbackAnimationId;
8530
- }
8531
- function syncRegisteredGsapAnimationsForClips(sequencePosition, clips) {
8532
- const enriched = [];
8533
- for (const clip of clips) {
8534
- const entry = getAnimationEntryBySheetAddressKey(
8535
- clip.sheetObjectAddressKey,
8536
- clip.gsapAnimationId
8537
- );
8538
- if (!entry?.animation) continue;
8539
- enriched.push({
8540
- ...clip,
8541
- entry,
8542
- targetKey: getGsapAnimationTargetKey(
8543
- entry.animation,
8544
- clip.gsapAnimationId
8545
- )
8546
- });
8547
- }
8548
- const byTarget = /* @__PURE__ */ new Map();
8549
- for (const item of enriched) {
8550
- const list = byTarget.get(item.targetKey) ?? [];
8551
- list.push(item);
8552
- byTarget.set(item.targetKey, list);
8553
- }
8554
- for (const group of byTarget.values()) {
8555
- const sorted = [...group].sort((a2, b2) => a2.start - b2.start);
8556
- for (const clip of sorted) {
8557
- const progress = gsapClipSyncProgress(sequencePosition, clip);
8558
- const entry = clip.entry;
8559
- const animation = entry.animation;
8560
- if (entry.kind === "timeline" && clip.timelineChildren && clip.timelineChildren.length > 0) {
8561
- applyTimelineChildTimingToGsap(
8562
- entry.animation,
8563
- clip.timelineChildren,
8564
- entry.timelineChildById,
8565
- entry.onRebuildTimeline
8566
- );
8567
- const span = clip.timelineSpan ?? readGsapTweenTimelineDuration(entry.animation);
8568
- const t2 = progress * Math.max(span, 0.01);
8569
- if (typeof animation.time === "function") {
8570
- animation.time(t2, true);
8571
- } else {
8572
- animation.progress?.(progress, true);
8573
- }
8574
- } else {
8575
- animation.progress?.(progress, true);
8576
- }
8577
- }
8578
- }
8579
- }
8580
- function readGsapTweenTimelineDuration(animation) {
8581
- const tween = animation;
8582
- const total = tween.totalDuration?.();
8583
- if (typeof total === "number" && total > 0) return total;
8584
- const d2 = tween.duration();
8585
- return d2 > 0 ? d2 : 1;
8586
- }
8587
-
8588
- // shared/src/gsap/gsapStudioRegistryRevision.ts
8589
- import { Atom as Atom11 } from "@unseenco/theatre-dataverse";
8590
- var revisionAtom = new Atom11(0);
8591
- var gsapStudioRegistryRevisionPointer = revisionAtom.pointer;
8592
-
8593
- // shared/src/gsap/gsapAnimationRegistry.ts
8594
- var DEFAULT_SHEET_INSTANCE_ID = "default";
8595
- var REGISTRY_KEY = "__unseenco_theatre_gsap_animationRegistry__";
8596
- function sheetObjectAddressKeyFromParts(address) {
8597
- const sheetInstanceId = address.sheetInstanceId ?? DEFAULT_SHEET_INSTANCE_ID;
8598
- return "".concat(address.projectId, "|").concat(address.sheetId, "|").concat(sheetInstanceId, "|").concat(address.objectKey);
8599
- }
8600
- function getStore() {
8601
- const g2 = globalThis;
8602
- if (!g2[REGISTRY_KEY]) {
8603
- g2[REGISTRY_KEY] = {
8604
- bySheetAddress: /* @__PURE__ */ new Map()
8605
- };
8606
- }
8607
- return g2[REGISTRY_KEY];
8608
- }
8609
- function getAnimationEntryBySheetAddressKey(sheetObjectAddressKey, animationId) {
8610
- return getStore().bySheetAddress.get(sheetObjectAddressKey)?.get(animationId);
8611
- }
8612
-
8613
- // shared/src/gsap/subscribeGsapClipSyncAtPlayhead.ts
8614
- import { pointerToPrism, prism as prism8, val as val10 } from "@unseenco/theatre-dataverse";
8615
-
8616
- // shared/src/gsap/syncGsapClipsAtSequencePosition.ts
8617
- function syncGsapClipsAtSequencePosition(position, clips) {
8618
- syncRegisteredGsapAnimationsForClips(
8619
- position,
8620
- clips
8621
- );
8622
- }
8623
-
8624
- // shared/src/gsap/subscribeGsapClipSyncAtPlayhead.ts
8625
- function subscribeGsapClipSyncAtPlayhead(source) {
8626
- const positionPointer = source.pointer.position;
8627
- const positionPrism = pointerToPrism(positionPointer);
8628
- const clipsPrism = prism8(() => source.getGsapClipTimings());
8629
- const syncNow = () => {
8630
- const clips = clipsPrism.getValue();
8631
- if (clips.length === 0) return;
8632
- syncGsapClipsAtSequencePosition(val10(positionPointer), clips);
8633
- };
8634
- const untapPosition = positionPrism.onStale(syncNow);
8635
- const untapClips = clipsPrism.onStale(syncNow);
8636
- syncNow();
8637
- return () => {
8638
- untapPosition();
8639
- untapClips();
8640
- };
8641
- }
8642
-
8643
- // core/src/gsap/attachGsapSequenceBridge.ts
8644
- function attachGsapSequenceBridge(sheet) {
8645
- const sequence = sheet.sequence;
8646
- const sheetAddress = privateAPI(sheet).address;
8647
- return subscribeGsapClipSyncAtPlayhead({
8648
- pointer: sequence.pointer,
8649
- getGsapClipTimings: () => sequence.__experimental_getGsapClips().map(({ objectKey, clip }) => ({
8650
- sheetObjectAddressKey: sheetObjectAddressKeyFromParts({
8651
- projectId: sheetAddress.projectId,
8652
- sheetId: sheetAddress.sheetId,
8653
- sheetInstanceId: sheetAddress.sheetInstanceId,
8654
- objectKey
8655
- }),
8656
- gsapAnimationId: clip.gsapAnimationId,
8657
- start: clip.start,
8658
- duration: clip.duration,
8659
- timelineChildren: clip.timelineChildren,
8660
- timelineSpan: clip.timelineSpan
8661
- }))
8662
- });
8663
- }
8664
-
8665
- // core/src/coreExports.ts
9449
+ import { isPrism, pointerToPrism as pointerToPrism3 } from "@unseenco/theatre-dataverse";
8666
9450
  function getProject(id, config = {}) {
8667
9451
  const existingProject = projectsSingleton_default.get(id);
8668
9452
  if (existingProject) {
@@ -8740,28 +9524,97 @@ var validateProjectIdOrThrow = (value) => {
8740
9524
  );
8741
9525
  }
8742
9526
  };
8743
- function onChange(pointer3, callback, rafDriver) {
9527
+ function onChange(pointer4, callback, rafDriver) {
8744
9528
  const ticker = rafDriver ? privateAPI(rafDriver).ticker : getCoreTicker();
8745
- if (isPointer(pointer3)) {
8746
- const pr = pointerToPrism2(pointer3);
9529
+ if (isPointer(pointer4)) {
9530
+ const pr = pointerToPrism3(pointer4);
8747
9531
  return pr.onChange(ticker, callback, true);
8748
- } else if (isPrism(pointer3)) {
8749
- return pointer3.onChange(ticker, callback, true);
9532
+ } else if (isPrism(pointer4)) {
9533
+ return pointer4.onChange(ticker, callback, true);
8750
9534
  } else {
8751
9535
  throw new Error(
8752
9536
  "Called onChange(p) where p is neither a pointer nor a prism."
8753
9537
  );
8754
9538
  }
8755
9539
  }
8756
- function val11(pointer3) {
8757
- if (isPointer(pointer3)) {
8758
- return pointerToPrism2(pointer3).getValue();
9540
+ function val14(pointer4) {
9541
+ if (isPointer(pointer4)) {
9542
+ return pointerToPrism3(pointer4).getValue();
8759
9543
  } else {
8760
9544
  throw new Error("Called val(p) where p is not a pointer.");
8761
9545
  }
8762
9546
  }
8763
9547
 
9548
+ // core/src/sheets/theatrePageScroll.ts
9549
+ var pageScrollConfig = {};
9550
+ function buildPageScrollContextFromConfig() {
9551
+ return {
9552
+ scroller: pageScrollConfig.scroller ?? defaultPageScrollContext.scroller,
9553
+ axis: pageScrollConfig.axis ?? defaultPageScrollContext.axis
9554
+ };
9555
+ }
9556
+ function configureTheatrePageScroll(config) {
9557
+ const prev = pageScrollConfig;
9558
+ pageScrollConfig = {
9559
+ scroller: config.scroller ?? prev.scroller,
9560
+ axis: config.axis ?? prev.axis
9561
+ };
9562
+ if (config.scroller !== void 0 || config.axis !== void 0) {
9563
+ setActivePageScrollContext(buildPageScrollContextFromConfig());
9564
+ }
9565
+ return {
9566
+ reset() {
9567
+ pageScrollConfig = prev;
9568
+ setActivePageScrollContext(
9569
+ prev.scroller !== void 0 || prev.axis !== void 0 ? {
9570
+ scroller: prev.scroller ?? defaultPageScrollContext.scroller,
9571
+ axis: prev.axis ?? defaultPageScrollContext.axis
9572
+ } : defaultPageScrollContext
9573
+ );
9574
+ }
9575
+ };
9576
+ }
9577
+ function getTheatrePageScrollConfig() {
9578
+ return pageScrollConfig;
9579
+ }
9580
+ function getTheatrePageScrollContext() {
9581
+ const ctx = buildPageScrollContextFromConfig();
9582
+ setActivePageScrollContext(ctx);
9583
+ return ctx;
9584
+ }
9585
+ function createDefaultPageScrollDriver(scroller = getTheatrePageScrollContext().scroller, axis = resolvePageScrollAxis(getTheatrePageScrollContext())) {
9586
+ if (typeof document !== "undefined" && scroller != null && !isNativeDocumentScroller(scroller) && scroller instanceof HTMLElement) {
9587
+ return axis === "horizontal" ? createElementHorizontalScrollDriver(scroller) : createElementScrollDriver(scroller);
9588
+ }
9589
+ return axis === "horizontal" ? createNativeDocumentHorizontalScrollDriver() : createNativeDocumentScrollDriver();
9590
+ }
9591
+ function attachTheatrePageScroll(sheet, options = {}) {
9592
+ const ctx = getTheatrePageScrollContext();
9593
+ const driver = options.driver ?? createDefaultPageScrollDriver(ctx.scroller, resolvePageScrollAxis(ctx));
9594
+ sheet.setPageScrollDriver(driver);
9595
+ return () => {
9596
+ sheet.setPageScrollDriver(void 0);
9597
+ };
9598
+ }
9599
+
9600
+ // core/src/coreExports-lite.ts
9601
+ var coreExports_lite_exports = {};
9602
+ __export(coreExports_lite_exports, {
9603
+ createRafDriver: () => createRafDriver,
9604
+ getProject: () => getProject,
9605
+ getTheatreCoreRafDriver: () => getTheatreCoreRafDriver,
9606
+ isRemoteEditorWindow: () => isRemoteEditorWindow,
9607
+ notify: () => notify,
9608
+ onChange: () => onChange,
9609
+ privateAPI: () => privateAPI,
9610
+ setCoreRafDriver: () => setCoreRafDriver,
9611
+ setPrivateAPI: () => setPrivateAPI,
9612
+ types: () => propTypes_exports,
9613
+ val: () => val14
9614
+ });
9615
+
8764
9616
  // core/src/CoreBundle.ts
9617
+ var coreExports = isTheatreLiteMode() ? coreExports_lite_exports : coreExports_exports;
8765
9618
  var CoreBundle = class {
8766
9619
  constructor() {
8767
9620
  __publicField(this, "_studio");
@@ -8770,7 +9623,7 @@ var CoreBundle = class {
8770
9623
  return "Theatre_CoreBundle";
8771
9624
  }
8772
9625
  get version() {
8773
- return "0.4.3";
9626
+ return "0.6.0";
8774
9627
  }
8775
9628
  getBitsForStudio(studio, callback) {
8776
9629
  if (this._studio) {
@@ -8782,7 +9635,7 @@ var CoreBundle = class {
8782
9635
  const bits = {
8783
9636
  projectsP: projectsSingleton_default.atom.pointer.projects,
8784
9637
  privateAPI,
8785
- coreExports: coreExports_exports,
9638
+ coreExports,
8786
9639
  getCoreRafDriver
8787
9640
  };
8788
9641
  callback(bits);
@@ -8793,6 +9646,15 @@ var CoreBundle = class {
8793
9646
  registerCoreBundle();
8794
9647
  function registerCoreBundle() {
8795
9648
  if (typeof window == "undefined") return;
9649
+ if (globalThis.__THEATRE_FORCE_LITE__) {
9650
+ const liteBundle = (
9651
+ // @ts-ignore ignore
9652
+ window[coreBundle]
9653
+ );
9654
+ if (liteBundle) {
9655
+ return;
9656
+ }
9657
+ }
8796
9658
  const existingBundle = (
8797
9659
  // @ts-ignore ignore
8798
9660
  window[coreBundle]
@@ -8819,17 +9681,44 @@ function registerCoreBundle() {
8819
9681
  }
8820
9682
  }
8821
9683
  export {
9684
+ PAGE_MODE_SEQUENCE_LENGTH,
9685
+ PAGE_MODE_SUB_UNITS_PER_UNIT,
8822
9686
  attachGsapSequenceBridge,
9687
+ attachSheetScrollDriver,
9688
+ attachTheatrePageScroll,
9689
+ configureTheatrePageScroll,
9690
+ createDefaultPageScrollDriver,
9691
+ createElementHorizontalScrollDriver,
9692
+ createElementScrollDriver,
9693
+ createNativeDocumentHorizontalScrollDriver,
9694
+ createNativeDocumentScrollDriver,
8823
9695
  createRafDriver,
9696
+ defaultPageScrollContext,
9697
+ getActivePageScrollContext,
8824
9698
  getProject,
9699
+ getSheetScrollDriver,
9700
+ getTheatreCoreRafDriver,
9701
+ getTheatrePageScrollConfig,
9702
+ getTheatrePageScrollContext,
9703
+ isNativeDocumentScroller,
9704
+ isPageScrollTrigger,
8825
9705
  isRemoteEditorWindow,
9706
+ isVerticalPageScrollTrigger,
8826
9707
  notify,
8827
9708
  onChange,
9709
+ pageScrollProgressFromSequence,
9710
+ pageScrollScrollersMatch,
8828
9711
  privateAPI,
9712
+ resolvePageScrollAxis,
9713
+ resolvePageScrollScroller,
9714
+ setActivePageScrollContext,
8829
9715
  setCoreRafDriver,
9716
+ setPageScrollProgress,
8830
9717
  setPrivateAPI,
9718
+ syncNativeDocumentScrollToSequencePosition,
9719
+ syncPageScrollToSequencePosition,
8831
9720
  propTypes_exports as types,
8832
- val11 as val
9721
+ val14 as val
8833
9722
  };
8834
9723
  /*! Bundled license information:
8835
9724