hyperframes 0.8.145 → 0.8.147
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/{add-B6OUH46W.js → add-5CNUY3EW.js} +15 -15
- package/dist/{animatedGifPrep-MIWRDJIO.js → animatedGifPrep-ZID2XJRQ.js} +10 -10
- package/dist/{asset-XJ2B2PU3.js → asset-TFEENZ7K.js} +2 -2
- package/dist/{assetCataloger-A5ZLSCMZ.js → assetCataloger-GX4B55VB.js} +4 -4
- package/dist/{auth-5HOVCZMV.js → auth-EJVZW6C3.js} +2 -2
- package/dist/{autoUpdate-WVNL5K3D.js → autoUpdate-MBNEZ2U4.js} +2 -2
- package/dist/{backgroundChecks-IGF54SFH.js → backgroundChecks-DNW5NPTY.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-T6JEGCQV.js → batchRender-T7S2CGJE.js} +5 -5
- package/dist/{beats-37T6Y6QP.js → beats-STXBGN6Z.js} +16 -16
- package/dist/{benchmark-ZVVLOWPP.js → benchmark-AC6IGEQP.js} +12 -12
- package/dist/{browser-4SSJOLH4.js → browser-FB5AK32T.js} +5 -5
- package/dist/{bundleWithLocalizedFonts-XWK423QP.js → bundleWithLocalizedFonts-HSCWGCFO.js} +2 -2
- package/dist/{capture-KZXOPBMO.js → capture-I24MXH3Y.js} +13 -13
- package/dist/{capture-2SF7YP57.js → capture-VEIVUHWB.js} +2 -2
- package/dist/{catalog-NLD4A2C6.js → catalog-JRC4VTTI.js} +15 -15
- package/dist/{catch-up-4BSRN6IR.js → catch-up-NTCK7Z3G.js} +6 -6
- package/dist/{check-IA44QQWM.js → check-7M7W4LPN.js} +38 -38
- package/dist/{checkBrowser-VM35KZMW.js → checkBrowser-2YRVCAYB.js} +118 -61
- package/dist/{chunk-OTHDVXOJ.js → chunk-2IDHEEAN.js} +3 -3
- package/dist/{chunk-VHFEMFYL.js → chunk-3BETQ4XI.js} +3 -3
- package/dist/{chunk-3KU3PFDW.js → chunk-3BYMCR4O.js} +85 -75
- package/dist/{chunk-FXJJCPPB.js → chunk-3HSWLZ6S.js} +1 -1
- package/dist/{chunk-ZF7SXQJ7.js → chunk-3PPO64IB.js} +2 -2
- package/dist/{chunk-PLR7Z6TC.js → chunk-3YUFN37G.js} +1 -1
- package/dist/{chunk-GRY3PN3K.js → chunk-4YVMMRHR.js} +2 -2
- package/dist/{chunk-ICKDMTLA.js → chunk-55RZG5SQ.js} +2 -2
- package/dist/{chunk-3IBMBNYY.js → chunk-5OKZLMQK.js} +10 -10
- package/dist/{chunk-DIRJ322I.js → chunk-66SAATRI.js} +3 -3
- package/dist/{chunk-GMAJB2P6.js → chunk-6BSIQJPW.js} +1 -1
- package/dist/{chunk-4QWD6JYN.js → chunk-6WD636E5.js} +3 -3
- package/dist/{chunk-5WVW7P23.js → chunk-A72OAGNB.js} +6 -6
- package/dist/{chunk-XBX4QJP7.js → chunk-AFIATIKS.js} +1 -1
- package/dist/{chunk-G75ENCEZ.js → chunk-AIJS74LG.js} +3 -3
- package/dist/{chunk-FBCULCAL.js → chunk-AL2YEVOT.js} +1 -1
- package/dist/{chunk-GEMJYBRU.js → chunk-B45OFFOQ.js} +2 -2
- package/dist/{chunk-VRW6EBHV.js → chunk-BAKPN2D2.js} +101 -94
- package/dist/{chunk-HB7FJOY4.js → chunk-BPUFVVSH.js} +1 -1
- package/dist/{chunk-BIAC7IJT.js → chunk-DDNS2674.js} +1 -1
- package/dist/{chunk-QFSCCQIR.js → chunk-DMKI64EZ.js} +1 -1
- package/dist/{chunk-EPE2HRJK.js → chunk-DYWSCPCR.js} +69 -64
- package/dist/{chunk-ZIYZ77MR.js → chunk-EGO6Z24R.js} +3 -3
- package/dist/{chunk-KC5XXX3X.js → chunk-EOOEC32M.js} +1 -1
- package/dist/{chunk-XIHCMVMG.js → chunk-FDL4HV44.js} +2 -2
- package/dist/{chunk-QZ3AZTXI.js → chunk-FJWEYVEM.js} +42 -16
- package/dist/{chunk-PUGIRFPX.js → chunk-FMNVTKX2.js} +4 -4
- package/dist/{chunk-IHTRYDFN.js → chunk-H7B6JSHI.js} +1 -1
- package/dist/{chunk-T42U2W2R.js → chunk-IXLUTE6N.js} +1 -1
- package/dist/{chunk-FDT6KQV4.js → chunk-JBQJKC23.js} +2 -2
- package/dist/{chunk-IEIJRMLZ.js → chunk-JDB65PPT.js} +62 -63
- package/dist/{chunk-UXO2L7HJ.js → chunk-JF5L5SQ6.js} +278 -65
- package/dist/{chunk-USDEMXXL.js → chunk-JYVGYKXG.js} +1 -1
- package/dist/{chunk-R42WWQVB.js → chunk-KPJMBC4K.js} +2 -2
- package/dist/{chunk-MAYCCGMQ.js → chunk-KVGDFUVO.js} +1 -1
- package/dist/{chunk-CFUXNBWH.js → chunk-LE7T4ML7.js} +1 -1
- package/dist/{chunk-MQZVBHEY.js → chunk-LFNQDTSH.js} +1 -1
- package/dist/{chunk-KIFHYXPB.js → chunk-MOL32UKR.js} +45 -11
- package/dist/{chunk-6LGNTUZN.js → chunk-N53FLAMZ.js} +7 -7
- package/dist/{chunk-ADF3X6GM.js → chunk-P6HELLPU.js} +2 -2
- package/dist/{chunk-5NRXZGKK.js → chunk-POKK6XXU.js} +9 -9
- package/dist/{chunk-GBGJ7A3D.js → chunk-QHRPB2JQ.js} +6 -6
- package/dist/{chunk-BFACGEII.js → chunk-QTTDKWSM.js} +2 -2
- package/dist/{chunk-U5QY7KTN.js → chunk-SEABQTBP.js} +11 -8
- package/dist/{chunk-ZEUONDQG.js → chunk-SYUGVPYH.js} +1 -1
- package/dist/{chunk-PJ3HDUCY.js → chunk-VAS6HQX3.js} +39 -9
- package/dist/{chunk-GQJZORQP.js → chunk-XBSPQ52S.js} +1 -1
- package/dist/{chunk-4ORLNTET.js → chunk-XOJDBRNF.js} +1 -1
- package/dist/{chunk-LAFJSYDL.js → chunk-XVIYZU3D.js} +1 -1
- package/dist/{chunk-OB5MJR4W.js → chunk-YCGU3UNU.js} +1 -1
- package/dist/{chunk-GXJEGZL2.js → chunk-Z5C4LEAD.js} +17 -18
- package/dist/chunk-Z6FLHIDV.js +3795 -0
- package/dist/{chunk-DDIVWXN7.js → chunk-ZFN6GQU4.js} +4 -4
- package/dist/{chunk-QLSM7K5S.js → chunk-ZLL72U3I.js} +2 -2
- package/dist/{chunk-ZSVUAVMT.js → chunk-ZQXNL5DL.js} +5 -5
- package/dist/{chunk-DWUKJQTO.js → chunk-ZVZSFDW3.js} +2 -2
- package/dist/{clean-RDKJB5FK.js → clean-3RY3Y2GX.js} +23 -23
- package/dist/cli.js +52 -52
- package/dist/{cloud-QVPVVNCW.js → cloud-MLPBFCVE.js} +4 -4
- package/dist/{cloudrun-3RE2UCQG.js → cloudrun-NQF5KFQI.js} +6 -6
- package/dist/{compare-LEDOY7MO.js → compare-6EZX2754.js} +32 -32
- package/dist/{compiler-F54OZZPM.js → compiler-ACCPOZMQ.js} +6 -6
- package/dist/{component-N42M67WY.js → component-F5PQHP6A.js} +3 -3
- package/dist/{compositions-VB2J2LZI.js → compositions-AUHWSI2H.js} +15 -15
- package/dist/{delete-Q6RWMJ4Z.js → delete-VUF4SHHJ.js} +2 -2
- package/dist/{deterministicFonts-U2BIMGPG.js → deterministicFonts-C5JQLCTS.js} +2 -2
- package/dist/{dist-Q4BI5A73.js → dist-GPDOV3IQ.js} +4 -4
- package/dist/{dist-KDJTFJHA.js → dist-HUMFCJ6T.js} +3 -3
- package/dist/{doctor-JMMUHDRV.js → doctor-3XHCA5JM.js} +15 -15
- package/dist/{events-RGUAHIBW.js → events-FKOIB3R3.js} +5 -5
- package/dist/{events-6ZBSIBE5.js → events-TIU72LZM.js} +4 -4
- package/dist/{feedback-FIID6MZW.js → feedback-V6VATYBE.js} +10 -10
- package/dist/{ffmpeg-T5SH2EFJ.js → ffmpeg-5V4FP3R6.js} +2 -2
- package/dist/{figma-BL3JJC36.js → figma-YBJM2VGE.js} +3 -3
- package/dist/fontLocalizeCli.js +14 -14
- package/dist/{get-P46GS7S6.js → get-3YVCGZBX.js} +2 -2
- package/dist/{gpuPolicy-AQ2BPLBK.js → gpuPolicy-ZOUG66M7.js} +10 -10
- package/dist/{grade-compare-GDCWU7ZZ.js → grade-compare-MYXIRKQI.js} +33 -33
- package/dist/{help-HJR3RWFG.js → help-WFZ2SUUR.js} +2 -2
- package/dist/{history-GGO5AWJB.js → history-HWPRJFR5.js} +49 -22
- package/dist/hyperframe-runtime.js +214 -68
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +214 -68
- package/dist/hyperframes-player.global.js +4 -5
- package/dist/hyperframes-slideshow.global.js +3 -4
- package/dist/{info-3GFWUBJC.js → info-WJDTQ4OZ.js} +11 -11
- package/dist/{init-36OPU2ZG.js → init-EXHDN7RO.js} +31 -31
- package/dist/{inspect-F2HEL5ON.js → inspect-EAOLZOMQ.js} +33 -33
- package/dist/{installer-NI6P6GC4.js → installer-LZ4X5TZZ.js} +6 -6
- package/dist/{keyframes-7OY3LMAZ.js → keyframes-FSZYNEDN.js} +8 -8
- package/dist/{lambda-6GJIWNJ3.js → lambda-3GAKHMC3.js} +7 -7
- package/dist/{layout-FTMLNL5A.js → layout-M2TQ2CIX.js} +33 -33
- package/dist/{lint-U6POHUON.js → lint-7C5UPTNQ.js} +11 -11
- package/dist/{lintProject-UBZ3TDHU.js → lintProject-SSEXWCH6.js} +3 -3
- package/dist/{list-IP5KI5Q2.js → list-GU5KBZ73.js} +2 -2
- package/dist/{login-4VWTVPHG.js → login-ZL2NYBIZ.js} +4 -4
- package/dist/{manager-YKMHR6LN.js → manager-5ORDVWJB.js} +3 -3
- package/dist/{media-treatment-XGV44AGV.js → media-treatment-QC3TAHVU.js} +82 -54
- package/dist/{models-UCXB6UR5.js → models-A54I4QR5.js} +14 -14
- package/dist/{motionShot-WPVNBXKA.js → motionShot-ZXPK562F.js} +35 -29
- package/dist/{normalize-audio-TYJ3UEHO.js → normalize-audio-CAP3DAE6.js} +10 -10
- package/dist/{open-HENOLVB2.js → open-GUSBNMDB.js} +6 -6
- package/dist/{parakeetRunner-VFQ6WFTD.js → parakeetRunner-GCCH72CO.js} +14 -14
- package/dist/{pipeline-6WPSC3H4.js → pipeline-SCJ2MWYH.js} +11 -11
- package/dist/{play-OI53WNUM.js → play-FP2QLMGM.js} +26 -26
- package/dist/{preflight-B4AFK3RG.js → preflight-ONF5AJNO.js} +5 -5
- package/dist/{present-NGMEQ4NO.js → present-H5SA4APW.js} +23 -23
- package/dist/{preview-VT2HWRWZ.js → preview-ATPVKA6K.js} +57 -26
- package/dist/{producer-7TYEAUF7.js → producer-VBYUC27R.js} +1 -1
- package/dist/{projectConfig-B2AF5DXY.js → projectConfig-SBRMQZGG.js} +8 -8
- package/dist/{publication-2PANQVC6.js → publication-5BQICRZO.js} +4 -4
- package/dist/{publish-O5OL42BG.js → publish-XDUZA3E3.js} +27 -26
- package/dist/{remove-background-T2JM6UVP.js → remove-background-GA6F7JZW.js} +12 -12
- package/dist/{render-Z253WHBK.js → render-KUVZFNQD.js} +27 -27
- package/dist/{render-W7OFXDOJ.js → render-PCFO45RK.js} +5 -5
- package/dist/{render-OLPKOJRU.js → render-XCYXFZTL.js} +12 -12
- package/dist/{render-batch-46IIBFKL.js → render-batch-7R2NRNVJ.js} +5 -5
- package/dist/{renderCancellation-QTZOCDJ2.js → renderCancellation-NIXEWRAO.js} +10 -10
- package/dist/renderSetupWorker.js +3 -3
- package/dist/{resolver-J2PL5FVJ.js → resolver-C4FPX72I.js} +6 -6
- package/dist/{sherpa-ZF42V3RN.js → sherpa-IQY52XU6.js} +14 -14
- package/dist/skills/media-use/references/media-treatments.md +5 -1
- package/dist/{skills-ACDOO3PX.js → skills-JSSAEKUW.js} +7 -7
- package/dist/{skillsUpdateCheck-L5OXVVPU.js → skillsUpdateCheck-XE5E2K2F.js} +3 -3
- package/dist/{slideshow-4OJEPWNZ.js → slideshow-YTWATJRT.js} +1 -1
- package/dist/{snapshot-UUVNZOW5.js → snapshot-QMQOE2DD.js} +34 -34
- package/dist/{src-BSLKXEGX.js → src-2GMPFYHL.js} +11 -9
- package/dist/{src-KS3AWFGT.js → src-R55QLGWI.js} +13 -13
- package/dist/{staticProjectServer-2TTVGPQH.js → staticProjectServer-YH2RHYKW.js} +20 -20
- package/dist/{status-LXPGSSKY.js → status-PTKNQD2E.js} +2 -2
- package/dist/studio/assets/{hyperframes-player-DZ5JrMDg.js → hyperframes-player-_eMxRXF_.js} +3 -3
- package/dist/studio/assets/{index-BqFRhNZa.js → index-6okhHdnH.js} +1 -1
- package/dist/studio/assets/{index-BOs6C0aZ.js → index-CEq9KmY2.js} +1 -1
- package/dist/studio/assets/{index-D8W0a0Z9.js → index-bXzd7tvF.js} +135 -135
- package/dist/studio/index.html +1 -1
- package/dist/{studio-api-WYWF7XRC.js → studio-api-T2TS2CHL.js} +16 -14
- package/dist/{studioServer-3FG4YTP7.js → studioServer-Q4MT44LT.js} +50 -50
- package/dist/{system-OQLOGGPJ.js → system-OXRG57F2.js} +2 -2
- package/dist/{telemetry-PAOOB4T4.js → telemetry-V5JYZDS4.js} +5 -5
- package/dist/{timeline-JIIJKKPC.js → timeline-KTCTOKF5.js} +34 -25
- package/dist/{tokens-3QRAM75Z.js → tokens-ZHREZPK6.js} +2 -2
- package/dist/{transcribe-QSBP5MUG.js → transcribe-4QDEWCE6.js} +12 -12
- package/dist/{transcribe-SZB6UMXE.js → transcribe-CRAV4FU3.js} +13 -13
- package/dist/{updateCheck-V3DSB26K.js → updateCheck-E7RMSK3E.js} +2 -2
- package/dist/{upgrade-L5GISOEV.js → upgrade-27PFTDCV.js} +2 -2
- package/dist/{urlDownloader-52FERT4X.js → urlDownloader-EAF6PLUP.js} +9 -9
- package/dist/{validate-HVVLX7KO.js → validate-OKNFDBMG.js} +27 -27
- package/dist/{video-MEOWRMFG.js → video-IEVS4FIH.js} +10 -10
- package/package.json +3 -2
- package/dist/chunk-AUWHD7RA.js +0 -3753
- package/dist/studio/chunk-6JY3MTIX.js +0 -1204
- package/dist/studio/chunk-EEXSYY5F.js +0 -190
- package/dist/studio/chunk-NZPJUZKT.js +0 -1538
- package/dist/studio/chunk-PZ5AY32C.js +0 -10
- package/dist/studio/chunk-TP6D3U37.js +0 -845
- package/dist/studio/chunk-Y2OHHNM2.js +0 -970
- package/dist/studio/domEditingLayers-PTP2ICGM.js +0 -47
- package/dist/studio/index.css +0 -165
- package/dist/studio/index.d.ts +0 -4318
- package/dist/studio/index.js +0 -100952
- package/dist/studio/player.d.ts +0 -30
- package/dist/studio/player.js +0 -10
- package/dist/studio/styles/tailwind-preset.d.ts +0 -39
- package/dist/studio/styles/tailwind-preset.js +0 -50
- package/dist/studio/styles.css +0 -1
- package/dist/studio/ui.d.ts +0 -297
- package/dist/studio/ui.js +0 -66
|
@@ -1,1538 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
HyperframesLoader
|
|
3
|
-
} from "./chunk-Y2OHHNM2.js";
|
|
4
|
-
import {
|
|
5
|
-
buildProjectApiPath,
|
|
6
|
-
splitTimelineElementKey,
|
|
7
|
-
studioApiFetch
|
|
8
|
-
} from "./chunk-6JY3MTIX.js";
|
|
9
|
-
|
|
10
|
-
// src/player/lib/time.ts
|
|
11
|
-
var STUDIO_PREVIEW_FPS = 30;
|
|
12
|
-
var clampToDuration = (time, duration) => Math.max(0, duration > 0 ? Math.min(duration, time) : time);
|
|
13
|
-
function formatTime(time) {
|
|
14
|
-
if (!Number.isFinite(time) || time < 0) return "00:00";
|
|
15
|
-
const mins = Math.floor(time / 60);
|
|
16
|
-
const secs = Math.floor(time % 60);
|
|
17
|
-
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
18
|
-
}
|
|
19
|
-
function secondsToFrame(time, fps = STUDIO_PREVIEW_FPS) {
|
|
20
|
-
if (!Number.isFinite(time) || time <= 0) return 0;
|
|
21
|
-
if (!Number.isFinite(fps) || fps <= 0) return 0;
|
|
22
|
-
return Math.round(time * fps);
|
|
23
|
-
}
|
|
24
|
-
function frameToSeconds(frame, fps = STUDIO_PREVIEW_FPS) {
|
|
25
|
-
if (!Number.isFinite(frame) || frame <= 0) return 0;
|
|
26
|
-
if (!Number.isFinite(fps) || fps <= 0) return 0;
|
|
27
|
-
return frame / fps;
|
|
28
|
-
}
|
|
29
|
-
function stepFrameTime(time, deltaFrames, fps = STUDIO_PREVIEW_FPS) {
|
|
30
|
-
const currentFrame = secondsToFrame(time, fps);
|
|
31
|
-
const nextFrame = Math.max(0, currentFrame + deltaFrames);
|
|
32
|
-
return frameToSeconds(nextFrame, fps);
|
|
33
|
-
}
|
|
34
|
-
function formatFrameTime(time, duration, fps = STUDIO_PREVIEW_FPS) {
|
|
35
|
-
const currentFrame = secondsToFrame(time, fps);
|
|
36
|
-
const totalFrames = secondsToFrame(duration, fps);
|
|
37
|
-
return `${currentFrame}f / ${totalFrames}f`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// src/player/store/liveTime.ts
|
|
41
|
-
var timeListeners = /* @__PURE__ */ new Set();
|
|
42
|
-
var latestTime = 0;
|
|
43
|
-
var seekCount = 0;
|
|
44
|
-
var liveTime = {
|
|
45
|
-
notify: (time) => {
|
|
46
|
-
latestTime = time;
|
|
47
|
-
timeListeners.forEach((listener) => listener(time));
|
|
48
|
-
},
|
|
49
|
-
notifySeek: (time) => {
|
|
50
|
-
seekCount += 1;
|
|
51
|
-
liveTime.notify(time);
|
|
52
|
-
},
|
|
53
|
-
seekCount: () => seekCount,
|
|
54
|
-
latest: () => latestTime,
|
|
55
|
-
subscribe: (listener) => {
|
|
56
|
-
timeListeners.add(listener);
|
|
57
|
-
return () => timeListeners.delete(listener);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// src/player/store/playerStore.ts
|
|
62
|
-
import { create } from "zustand";
|
|
63
|
-
|
|
64
|
-
// src/player/store/playerStoreDevHandle.ts
|
|
65
|
-
function isDevBuild() {
|
|
66
|
-
try {
|
|
67
|
-
return import.meta.env.DEV === true;
|
|
68
|
-
} catch {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function attachPlayerStoreDevHandle(store) {
|
|
73
|
-
if (!isDevBuild() || typeof window === "undefined") return;
|
|
74
|
-
window.__playerStore = store;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/player/store/playerStoreSelection.ts
|
|
78
|
-
function nextSelectionSet(current, id, preserveSet) {
|
|
79
|
-
if (preserveSet) return id && current.has(id) ? new Set(current) : /* @__PURE__ */ new Set();
|
|
80
|
-
return id ? /* @__PURE__ */ new Set([id]) : /* @__PURE__ */ new Set();
|
|
81
|
-
}
|
|
82
|
-
function revealTargetsSelection(request, id) {
|
|
83
|
-
if (!request || id === null) return false;
|
|
84
|
-
return request.elementKey === splitTimelineElementKey(id).domId;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/components/dock/panelRegistry.ts
|
|
88
|
-
var PANEL_IDS = [
|
|
89
|
-
"preview",
|
|
90
|
-
"timeline",
|
|
91
|
-
"compositions",
|
|
92
|
-
"assets",
|
|
93
|
-
"code",
|
|
94
|
-
"catalog",
|
|
95
|
-
"design",
|
|
96
|
-
"layers",
|
|
97
|
-
"renders",
|
|
98
|
-
"variables",
|
|
99
|
-
"slideshow"
|
|
100
|
-
];
|
|
101
|
-
var PANEL_DEFINITIONS = {
|
|
102
|
-
preview: {
|
|
103
|
-
title: "Preview",
|
|
104
|
-
zone: "center",
|
|
105
|
-
reopen: { near: "timeline", direction: "above" },
|
|
106
|
-
keepMounted: true
|
|
107
|
-
},
|
|
108
|
-
timeline: {
|
|
109
|
-
title: "Timeline",
|
|
110
|
-
zone: "center",
|
|
111
|
-
reopen: { near: "preview", direction: "below" },
|
|
112
|
-
keepMounted: true
|
|
113
|
-
},
|
|
114
|
-
compositions: {
|
|
115
|
-
title: "Compositions",
|
|
116
|
-
zone: "left",
|
|
117
|
-
reopen: { near: "preview", direction: "left" }
|
|
118
|
-
},
|
|
119
|
-
assets: { title: "Assets", zone: "left", reopen: { near: "compositions", direction: "within" } },
|
|
120
|
-
code: { title: "Code", zone: "left", reopen: { near: "compositions", direction: "within" } },
|
|
121
|
-
catalog: {
|
|
122
|
-
title: "Catalog",
|
|
123
|
-
zone: "left",
|
|
124
|
-
reopen: { near: "compositions", direction: "within" }
|
|
125
|
-
},
|
|
126
|
-
design: { title: "Design", zone: "right", reopen: { near: "preview", direction: "right" } },
|
|
127
|
-
layers: { title: "Layers", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
128
|
-
renders: { title: "Renders", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
129
|
-
variables: { title: "Variables", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
130
|
-
slideshow: { title: "Slideshow", zone: "right", reopen: { near: "design", direction: "within" } }
|
|
131
|
-
};
|
|
132
|
-
function isPanelId(value) {
|
|
133
|
-
return typeof value === "string" && PANEL_IDS.includes(value);
|
|
134
|
-
}
|
|
135
|
-
function panelsInZone(zone) {
|
|
136
|
-
return PANEL_IDS.filter((id) => PANEL_DEFINITIONS[id].zone === zone);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// src/components/dock/dockLayoutSchema.ts
|
|
140
|
-
var DOCK_PANEL_COMPONENT = "panel";
|
|
141
|
-
function isRecord(value) {
|
|
142
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
143
|
-
}
|
|
144
|
-
function collectLeafViews(node, into) {
|
|
145
|
-
if (!isRecord(node)) return false;
|
|
146
|
-
if (node.type === "leaf") {
|
|
147
|
-
if (!isRecord(node.data) || !Array.isArray(node.data.views)) return false;
|
|
148
|
-
into.push(...node.data.views);
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
if (node.type === "branch") {
|
|
152
|
-
return Array.isArray(node.data) && node.data.every((child) => collectLeafViews(child, into));
|
|
153
|
-
}
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
function hasGridShape(grid) {
|
|
157
|
-
const oriented = grid.orientation === "HORIZONTAL" || grid.orientation === "VERTICAL";
|
|
158
|
-
return oriented && typeof grid.width === "number" && typeof grid.height === "number";
|
|
159
|
-
}
|
|
160
|
-
function panelsAreRegistered(panels, allowed) {
|
|
161
|
-
const ids = Object.keys(panels);
|
|
162
|
-
return ids.length > 0 && ids.every((id) => {
|
|
163
|
-
const state = panels[id];
|
|
164
|
-
return isPanelId(id) && allowed.includes(id) && isRecord(state) && state.id === id && state.contentComponent === DOCK_PANEL_COMPONENT;
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
function collectFloatingViews(floating, into) {
|
|
168
|
-
if (floating === void 0) return true;
|
|
169
|
-
if (!Array.isArray(floating)) return false;
|
|
170
|
-
return floating.every((group) => {
|
|
171
|
-
if (!isRecord(group) || !isRecord(group.data) || !Array.isArray(group.data.views)) return false;
|
|
172
|
-
into.push(...group.data.views);
|
|
173
|
-
return true;
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
function parseDockLayout(value, allowed = PANEL_IDS) {
|
|
177
|
-
if (!isRecord(value) || !isRecord(value.grid) || !isRecord(value.panels)) return null;
|
|
178
|
-
const { grid, panels } = value;
|
|
179
|
-
if (!hasGridShape(grid) || !panelsAreRegistered(panels, allowed)) return null;
|
|
180
|
-
const views = [];
|
|
181
|
-
if (!collectLeafViews(grid.root, views)) return null;
|
|
182
|
-
if (!collectFloatingViews(value.floatingGroups, views)) return null;
|
|
183
|
-
const everyViewIsAPanel = views.every((id) => typeof id === "string" && id in panels);
|
|
184
|
-
const everyPanelIsPlaced = Object.keys(panels).every((id) => views.includes(id));
|
|
185
|
-
return everyViewIsAPanel && everyPanelIsPlaced ? value : null;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// src/utils/studioUiPreferences.ts
|
|
189
|
-
var STUDIO_UI_PREFERENCES_KEY = "hf-studio-ui-preferences";
|
|
190
|
-
function isRecord2(value) {
|
|
191
|
-
return typeof value === "object" && value !== null;
|
|
192
|
-
}
|
|
193
|
-
function getBrowserStorage() {
|
|
194
|
-
if (typeof window === "undefined") return null;
|
|
195
|
-
try {
|
|
196
|
-
return window.localStorage;
|
|
197
|
-
} catch {
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
function storageKeyFor(projectId, key) {
|
|
202
|
-
return projectId ? `${key}:${projectId}` : key;
|
|
203
|
-
}
|
|
204
|
-
function readStorage(storage, key) {
|
|
205
|
-
if (!storage) return {};
|
|
206
|
-
try {
|
|
207
|
-
const raw = storage.getItem(key);
|
|
208
|
-
if (!raw) return {};
|
|
209
|
-
const parsed = JSON.parse(raw);
|
|
210
|
-
if (!isRecord2(parsed)) return {};
|
|
211
|
-
const preferences = {};
|
|
212
|
-
if (typeof parsed.timelineVisible === "boolean") {
|
|
213
|
-
preferences.timelineVisible = parsed.timelineVisible;
|
|
214
|
-
}
|
|
215
|
-
if (typeof parsed.playbackRate === "number" && Number.isFinite(parsed.playbackRate)) {
|
|
216
|
-
preferences.playbackRate = parsed.playbackRate;
|
|
217
|
-
}
|
|
218
|
-
if (typeof parsed.audioMuted === "boolean") {
|
|
219
|
-
preferences.audioMuted = parsed.audioMuted;
|
|
220
|
-
}
|
|
221
|
-
if (typeof parsed.audioVolume === "number" && Number.isFinite(parsed.audioVolume) && parsed.audioVolume >= 0 && parsed.audioVolume <= 1) {
|
|
222
|
-
preferences.audioVolume = parsed.audioVolume;
|
|
223
|
-
}
|
|
224
|
-
if (parsed.thumbnailMode === "adaptive" || parsed.thumbnailMode === "hidden") {
|
|
225
|
-
preferences.thumbnailMode = parsed.thumbnailMode;
|
|
226
|
-
} else if (typeof parsed.thumbnailsEnabled === "boolean") {
|
|
227
|
-
preferences.thumbnailMode = parsed.thumbnailsEnabled ? "adaptive" : "hidden";
|
|
228
|
-
}
|
|
229
|
-
if (Array.isArray(parsed.recentBlocks)) {
|
|
230
|
-
preferences.recentBlocks = parsed.recentBlocks.filter(
|
|
231
|
-
(v) => typeof v === "string"
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
if (typeof parsed.snapEnabled === "boolean") {
|
|
235
|
-
preferences.snapEnabled = parsed.snapEnabled;
|
|
236
|
-
}
|
|
237
|
-
if (typeof parsed.gridVisible === "boolean") {
|
|
238
|
-
preferences.gridVisible = parsed.gridVisible;
|
|
239
|
-
}
|
|
240
|
-
if (typeof parsed.rulerVisible === "boolean") {
|
|
241
|
-
preferences.rulerVisible = parsed.rulerVisible;
|
|
242
|
-
}
|
|
243
|
-
if (typeof parsed.safeMarginsVisible === "boolean") {
|
|
244
|
-
preferences.safeMarginsVisible = parsed.safeMarginsVisible;
|
|
245
|
-
}
|
|
246
|
-
if (typeof parsed.gridSpacing === "number" && Number.isFinite(parsed.gridSpacing)) {
|
|
247
|
-
preferences.gridSpacing = parsed.gridSpacing;
|
|
248
|
-
}
|
|
249
|
-
if (typeof parsed.snapToGrid === "boolean") {
|
|
250
|
-
preferences.snapToGrid = parsed.snapToGrid;
|
|
251
|
-
}
|
|
252
|
-
if (typeof parsed.timelineSnapEnabled === "boolean") {
|
|
253
|
-
preferences.timelineSnapEnabled = parsed.timelineSnapEnabled;
|
|
254
|
-
}
|
|
255
|
-
if (typeof parsed.audioMetersVisible === "boolean") {
|
|
256
|
-
preferences.audioMetersVisible = parsed.audioMetersVisible;
|
|
257
|
-
}
|
|
258
|
-
if (typeof parsed.rippleEditEnabled === "boolean") {
|
|
259
|
-
preferences.rippleEditEnabled = parsed.rippleEditEnabled;
|
|
260
|
-
}
|
|
261
|
-
if (parsed.theme === "light" || parsed.theme === "dark") preferences.theme = parsed.theme;
|
|
262
|
-
if (parsed.timeDisplayMode === "time" || parsed.timeDisplayMode === "frame") {
|
|
263
|
-
preferences.timeDisplayMode = parsed.timeDisplayMode;
|
|
264
|
-
}
|
|
265
|
-
if (parsed.timelineZoomMode === "fit" || parsed.timelineZoomMode === "manual") {
|
|
266
|
-
preferences.timelineZoomMode = parsed.timelineZoomMode;
|
|
267
|
-
}
|
|
268
|
-
if (typeof parsed.timelineManualZoomPercent === "number" && Number.isFinite(parsed.timelineManualZoomPercent)) {
|
|
269
|
-
preferences.timelineManualZoomPercent = parsed.timelineManualZoomPercent;
|
|
270
|
-
}
|
|
271
|
-
if (typeof parsed.agentToolsEnabled === "boolean") {
|
|
272
|
-
preferences.agentToolsEnabled = parsed.agentToolsEnabled;
|
|
273
|
-
}
|
|
274
|
-
if (typeof parsed.linkedSelectionEnabled === "boolean") {
|
|
275
|
-
preferences.linkedSelectionEnabled = parsed.linkedSelectionEnabled;
|
|
276
|
-
}
|
|
277
|
-
if (typeof parsed.syncIndicatorsVisible === "boolean") {
|
|
278
|
-
preferences.syncIndicatorsVisible = parsed.syncIndicatorsVisible;
|
|
279
|
-
}
|
|
280
|
-
const dockLayout = parseDockLayout(parsed.dockLayout);
|
|
281
|
-
if (dockLayout) preferences.dockLayout = dockLayout;
|
|
282
|
-
return preferences;
|
|
283
|
-
} catch {
|
|
284
|
-
return {};
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function readStudioUiPreferences(storage = getBrowserStorage(), projectId = null, key = STUDIO_UI_PREFERENCES_KEY) {
|
|
288
|
-
const scoped = readStorage(storage, storageKeyFor(projectId, key));
|
|
289
|
-
if (!projectId || Object.keys(scoped).length > 0) return scoped;
|
|
290
|
-
return readStorage(storage, key);
|
|
291
|
-
}
|
|
292
|
-
function writeStudioUiPreferences(patch, storage = getBrowserStorage(), projectId = null, key = STUDIO_UI_PREFERENCES_KEY) {
|
|
293
|
-
if (!storage) return;
|
|
294
|
-
try {
|
|
295
|
-
const next = {
|
|
296
|
-
...readStudioUiPreferences(storage, projectId, key),
|
|
297
|
-
...patch
|
|
298
|
-
};
|
|
299
|
-
storage.setItem(storageKeyFor(projectId, key), JSON.stringify(next));
|
|
300
|
-
} catch {
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// src/player/components/timelineZoom.ts
|
|
305
|
-
var MIN_TIMELINE_ZOOM_PERCENT = 10;
|
|
306
|
-
var MAX_TIMELINE_FRAME_WIDTH_PX = 48;
|
|
307
|
-
var ZOOM_OUT_FACTOR = 0.5;
|
|
308
|
-
var ZOOM_IN_FACTOR = 2;
|
|
309
|
-
var PINCH_ZOOM_SENSITIVITY = 0.014;
|
|
310
|
-
function getMaxTimelineZoomPercent(fitPixelsPerSecond) {
|
|
311
|
-
if (!Number.isFinite(fitPixelsPerSecond) || fitPixelsPerSecond <= 0) return 100;
|
|
312
|
-
const frameLevelPixelsPerSecond = STUDIO_PREVIEW_FPS * MAX_TIMELINE_FRAME_WIDTH_PX;
|
|
313
|
-
return Math.max(100, Math.round(frameLevelPixelsPerSecond / fitPixelsPerSecond * 100));
|
|
314
|
-
}
|
|
315
|
-
function clampTimelineZoomPercent(percent, fitPixelsPerSecond) {
|
|
316
|
-
if (!Number.isFinite(percent)) return 100;
|
|
317
|
-
const maxZoomPercent = getMaxTimelineZoomPercent(fitPixelsPerSecond);
|
|
318
|
-
return Math.max(MIN_TIMELINE_ZOOM_PERCENT, Math.min(maxZoomPercent, Math.round(percent)));
|
|
319
|
-
}
|
|
320
|
-
function getTimelineZoomPercent(zoomMode, manualZoomPercent, fitPixelsPerSecond) {
|
|
321
|
-
return zoomMode === "fit" ? 100 : clampTimelineZoomPercent(manualZoomPercent, fitPixelsPerSecond);
|
|
322
|
-
}
|
|
323
|
-
function computePinnedZoomPercent(currentPixelsPerSecond, fitPixelsPerSecond) {
|
|
324
|
-
if (!Number.isFinite(currentPixelsPerSecond) || currentPixelsPerSecond <= 0 || !Number.isFinite(fitPixelsPerSecond) || fitPixelsPerSecond <= 0) {
|
|
325
|
-
return 100;
|
|
326
|
-
}
|
|
327
|
-
return clampTimelineZoomPercent(
|
|
328
|
-
currentPixelsPerSecond / fitPixelsPerSecond * 100,
|
|
329
|
-
fitPixelsPerSecond
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
function getTimelinePixelsPerSecond(fitPixelsPerSecond, zoomMode, manualZoomPercent) {
|
|
333
|
-
if (!Number.isFinite(fitPixelsPerSecond) || fitPixelsPerSecond <= 0) return 100;
|
|
334
|
-
const zoomPercent = getTimelineZoomPercent(zoomMode, manualZoomPercent, fitPixelsPerSecond);
|
|
335
|
-
return zoomMode === "fit" ? fitPixelsPerSecond : fitPixelsPerSecond * (zoomPercent / 100);
|
|
336
|
-
}
|
|
337
|
-
function getNextTimelineZoomPercent(direction, zoomMode, manualZoomPercent, fitPixelsPerSecond) {
|
|
338
|
-
const current = getTimelineZoomPercent(zoomMode, manualZoomPercent, fitPixelsPerSecond);
|
|
339
|
-
const next = direction === "in" ? current * ZOOM_IN_FACTOR : current * ZOOM_OUT_FACTOR;
|
|
340
|
-
return clampTimelineZoomPercent(next, fitPixelsPerSecond);
|
|
341
|
-
}
|
|
342
|
-
function getPinchTimelineZoomPercent(deltaY, zoomMode, manualZoomPercent, fitPixelsPerSecond) {
|
|
343
|
-
const current = getTimelineZoomPercent(zoomMode, manualZoomPercent, fitPixelsPerSecond);
|
|
344
|
-
if (!Number.isFinite(deltaY) || deltaY === 0) return current;
|
|
345
|
-
return clampTimelineZoomPercent(
|
|
346
|
-
current * Math.exp(-deltaY * PINCH_ZOOM_SENSITIVITY),
|
|
347
|
-
fitPixelsPerSecond
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
var LOG_MIN = Math.log(MIN_TIMELINE_ZOOM_PERCENT);
|
|
351
|
-
function timelineZoomPercentToSlider(percent, fitPixelsPerSecond) {
|
|
352
|
-
const clamped = clampTimelineZoomPercent(percent, fitPixelsPerSecond);
|
|
353
|
-
const logMax = Math.log(getMaxTimelineZoomPercent(fitPixelsPerSecond));
|
|
354
|
-
return (Math.log(clamped) - LOG_MIN) / (logMax - LOG_MIN) * 100;
|
|
355
|
-
}
|
|
356
|
-
function timelineSliderToZoomPercent(slider, fitPixelsPerSecond) {
|
|
357
|
-
const clampedSlider = Math.max(0, Math.min(100, slider));
|
|
358
|
-
const logMax = Math.log(getMaxTimelineZoomPercent(fitPixelsPerSecond));
|
|
359
|
-
const logValue = LOG_MIN + clampedSlider / 100 * (logMax - LOG_MIN);
|
|
360
|
-
return clampTimelineZoomPercent(Math.exp(logValue), fitPixelsPerSecond);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// src/player/store/keyframeSlice.ts
|
|
364
|
-
function isRevealedAudioFxRequestCurrent(request, state) {
|
|
365
|
-
return request.projectId === state.timelineProjectId && request.sessionEpoch === state.timelineSessionEpoch;
|
|
366
|
-
}
|
|
367
|
-
function isFocusedEaseRequestCurrent(request, state) {
|
|
368
|
-
return request.projectId === state.timelineProjectId && request.sessionEpoch === state.timelineSessionEpoch && request.elementId === state.selectedElementId;
|
|
369
|
-
}
|
|
370
|
-
function createKeyframeSlice(set, getTimelineSessionIdentity) {
|
|
371
|
-
return {
|
|
372
|
-
selectedKeyframes: /* @__PURE__ */ new Set(),
|
|
373
|
-
toggleSelectedKeyframe: (key) => set((state) => {
|
|
374
|
-
const next = new Set(state.selectedKeyframes);
|
|
375
|
-
if (next.has(key)) next.delete(key);
|
|
376
|
-
else next.add(key);
|
|
377
|
-
return { selectedKeyframes: next };
|
|
378
|
-
}),
|
|
379
|
-
clearSelectedKeyframes: () => set({ selectedKeyframes: /* @__PURE__ */ new Set() }),
|
|
380
|
-
expandedClipIds: /* @__PURE__ */ new Set(),
|
|
381
|
-
toggleClipExpanded: (id) => set((state) => {
|
|
382
|
-
const next = new Set(state.expandedClipIds);
|
|
383
|
-
if (next.has(id)) next.delete(id);
|
|
384
|
-
else next.add(id);
|
|
385
|
-
return { expandedClipIds: next };
|
|
386
|
-
}),
|
|
387
|
-
setClipExpanded: (id, expanded) => set((state) => {
|
|
388
|
-
if (state.expandedClipIds.has(id) === expanded) return state;
|
|
389
|
-
const next = new Set(state.expandedClipIds);
|
|
390
|
-
if (expanded) next.add(id);
|
|
391
|
-
else next.delete(id);
|
|
392
|
-
return { expandedClipIds: next };
|
|
393
|
-
}),
|
|
394
|
-
expandClips: (ids) => set((state) => {
|
|
395
|
-
if (ids.every((id) => state.expandedClipIds.has(id))) return state;
|
|
396
|
-
const next = new Set(state.expandedClipIds);
|
|
397
|
-
for (const id of ids) next.add(id);
|
|
398
|
-
return { expandedClipIds: next };
|
|
399
|
-
}),
|
|
400
|
-
collapsedGroupIds: /* @__PURE__ */ new Set(),
|
|
401
|
-
toggleGroupExpanded: (id) => set((state) => {
|
|
402
|
-
const next = new Set(state.collapsedGroupIds);
|
|
403
|
-
if (next.has(id)) next.delete(id);
|
|
404
|
-
else next.add(id);
|
|
405
|
-
return { collapsedGroupIds: next };
|
|
406
|
-
}),
|
|
407
|
-
expandedLaneOwnerIds: /* @__PURE__ */ new Set(),
|
|
408
|
-
toggleLaneOwnerExpanded: (id) => set((state) => {
|
|
409
|
-
const next = new Set(state.expandedLaneOwnerIds);
|
|
410
|
-
if (next.has(id)) next.delete(id);
|
|
411
|
-
else next.add(id);
|
|
412
|
-
return { expandedLaneOwnerIds: next };
|
|
413
|
-
}),
|
|
414
|
-
focusedEaseSegment: null,
|
|
415
|
-
focusedEaseRequestNonce: 0,
|
|
416
|
-
setFocusedEaseSegment: (target) => set((state) => {
|
|
417
|
-
const nonce = state.focusedEaseRequestNonce + 1;
|
|
418
|
-
const { timelineProjectId, timelineSessionEpoch } = getTimelineSessionIdentity();
|
|
419
|
-
return {
|
|
420
|
-
focusedEaseRequestNonce: nonce,
|
|
421
|
-
focusedEaseSegment: {
|
|
422
|
-
...target,
|
|
423
|
-
projectId: timelineProjectId,
|
|
424
|
-
sessionEpoch: timelineSessionEpoch,
|
|
425
|
-
nonce
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
}),
|
|
429
|
-
clearFocusedEaseSegment: (nonce) => set(
|
|
430
|
-
(state) => state.focusedEaseSegment?.nonce === nonce ? { focusedEaseSegment: null } : state
|
|
431
|
-
),
|
|
432
|
-
revealedAudioFxTarget: null,
|
|
433
|
-
revealedAudioFxNonce: 0,
|
|
434
|
-
setRevealedAudioFxTarget: (target) => set((state) => {
|
|
435
|
-
const nonce = state.revealedAudioFxNonce + 1;
|
|
436
|
-
const { timelineProjectId, timelineSessionEpoch } = getTimelineSessionIdentity();
|
|
437
|
-
return {
|
|
438
|
-
revealedAudioFxNonce: nonce,
|
|
439
|
-
revealedAudioFxTarget: {
|
|
440
|
-
...target,
|
|
441
|
-
projectId: timelineProjectId,
|
|
442
|
-
sessionEpoch: timelineSessionEpoch,
|
|
443
|
-
nonce
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
}),
|
|
447
|
-
clearRevealedAudioFxTarget: (nonce) => set(
|
|
448
|
-
(state) => state.revealedAudioFxTarget?.nonce === nonce ? { revealedAudioFxTarget: null } : state
|
|
449
|
-
),
|
|
450
|
-
keyframeCache: /* @__PURE__ */ new Map(),
|
|
451
|
-
setKeyframeCache: (elementId, data) => set((state) => {
|
|
452
|
-
if (data ? state.keyframeCache.get(elementId) === data : !state.keyframeCache.has(elementId))
|
|
453
|
-
return state;
|
|
454
|
-
const next = new Map(state.keyframeCache);
|
|
455
|
-
if (data) next.set(elementId, data);
|
|
456
|
-
else next.delete(elementId);
|
|
457
|
-
return { keyframeCache: next };
|
|
458
|
-
}),
|
|
459
|
-
gsapAnimations: /* @__PURE__ */ new Map(),
|
|
460
|
-
setGsapAnimations: (elementId, animations) => set((state) => {
|
|
461
|
-
if (animations ? state.gsapAnimations.get(elementId) === animations : !state.gsapAnimations.has(elementId))
|
|
462
|
-
return state;
|
|
463
|
-
const next = new Map(state.gsapAnimations);
|
|
464
|
-
if (animations) next.set(elementId, animations);
|
|
465
|
-
else next.delete(elementId);
|
|
466
|
-
return { gsapAnimations: next };
|
|
467
|
-
})
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// src/player/store/automationSelectionSlice.ts
|
|
472
|
-
function createAutomationSelectionSlice(set) {
|
|
473
|
-
return {
|
|
474
|
-
automationSelection: null,
|
|
475
|
-
setAutomationSelection: (sel) => set({
|
|
476
|
-
automationSelection: {
|
|
477
|
-
...sel,
|
|
478
|
-
t0: Math.min(sel.t0, sel.t1),
|
|
479
|
-
t1: Math.max(sel.t0, sel.t1),
|
|
480
|
-
v0: Math.min(sel.v0, sel.v1),
|
|
481
|
-
v1: Math.max(sel.v0, sel.v1)
|
|
482
|
-
}
|
|
483
|
-
}),
|
|
484
|
-
clearAutomationSelection: () => set({ automationSelection: null })
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// src/player/store/editingModeSlice.ts
|
|
489
|
-
function createEditingModeSlice(set) {
|
|
490
|
-
return {
|
|
491
|
-
motionPathArmed: false,
|
|
492
|
-
setMotionPathArmed: (armed) => set({ motionPathArmed: armed }),
|
|
493
|
-
motionPathCreateAvailable: false,
|
|
494
|
-
setMotionPathCreateAvailable: (available) => set({ motionPathCreateAvailable: available }),
|
|
495
|
-
autoKeyframeEnabled: true,
|
|
496
|
-
setAutoKeyframeEnabled: (enabled) => set({ autoKeyframeEnabled: enabled })
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// src/player/store/timelineFocusState.ts
|
|
501
|
-
function createTimelineFocusRequest(id, projectId, sessionEpoch, nonce) {
|
|
502
|
-
return { id, projectId, sessionEpoch, nonce };
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// src/player/lib/thumbnailPolicy.ts
|
|
506
|
-
var rawPolicy = import.meta.env?.VITE_STUDIO_TIMELINE_THUMBNAIL_POLICY;
|
|
507
|
-
var studioThumbnailRuntimePolicy = rawPolicy === "force-hidden" || rawPolicy === "legacy-default" ? rawPolicy : "follow-preference";
|
|
508
|
-
function defaultThumbnailMode(storedMode, policy = studioThumbnailRuntimePolicy) {
|
|
509
|
-
return storedMode ?? (policy === "legacy-default" ? "hidden" : "adaptive");
|
|
510
|
-
}
|
|
511
|
-
function effectiveThumbnailMode(preferredMode, policy = studioThumbnailRuntimePolicy) {
|
|
512
|
-
return policy === "force-hidden" ? "hidden" : preferredMode;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// src/player/store/thumbnailSlice.ts
|
|
516
|
-
var EVERY_COMPOSITION = "*";
|
|
517
|
-
function revisionKey(path) {
|
|
518
|
-
return (path.split(/[?#]/)[0] ?? "").replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
519
|
-
}
|
|
520
|
-
function thumbnailRevisionOf(revisions, compositionPath) {
|
|
521
|
-
return (revisions[EVERY_COMPOSITION] ?? 0) + (revisions[revisionKey(compositionPath)] ?? 0);
|
|
522
|
-
}
|
|
523
|
-
function createThumbnailSlice(set) {
|
|
524
|
-
return {
|
|
525
|
-
thumbnailMode: defaultThumbnailMode(readStudioUiPreferences().thumbnailMode),
|
|
526
|
-
thumbnailRevisions: {},
|
|
527
|
-
setThumbnailMode: (mode) => {
|
|
528
|
-
writeStudioUiPreferences({ thumbnailMode: mode });
|
|
529
|
-
set({ thumbnailMode: mode });
|
|
530
|
-
},
|
|
531
|
-
bumpThumbnailRevisions: (compositions) => set(({ thumbnailRevisions }) => {
|
|
532
|
-
const next = { ...thumbnailRevisions };
|
|
533
|
-
for (const path of compositions?.map(revisionKey) ?? [EVERY_COMPOSITION]) {
|
|
534
|
-
next[path] = (next[path] ?? 0) + 1;
|
|
535
|
-
}
|
|
536
|
-
return { thumbnailRevisions: next };
|
|
537
|
-
})
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// src/player/store/readinessSlice.ts
|
|
542
|
-
import { settleCompositionReadiness } from "@hyperframes/core/composition-readiness";
|
|
543
|
-
var timelineReadyGeneration = 0;
|
|
544
|
-
var loadStepDocs = /* @__PURE__ */ new WeakSet();
|
|
545
|
-
var awaitingLoadStep = null;
|
|
546
|
-
function resetPlaybackReadinessState() {
|
|
547
|
-
timelineReadyGeneration++;
|
|
548
|
-
return { timelineReady: false, previewBooted: false };
|
|
549
|
-
}
|
|
550
|
-
function createPlaybackReadinessSlice(set) {
|
|
551
|
-
const settle = (doc, generation) => settleCompositionReadiness(doc, () => {
|
|
552
|
-
if (generation === timelineReadyGeneration) set({ timelineReady: true });
|
|
553
|
-
});
|
|
554
|
-
return {
|
|
555
|
-
timelineReady: false,
|
|
556
|
-
previewBooted: false,
|
|
557
|
-
markPreviewBooted: () => set({ previewBooted: true }),
|
|
558
|
-
playLocked: false,
|
|
559
|
-
setPlayLocked: (locked) => set({ playLocked: locked }),
|
|
560
|
-
setTimelineReady: (ready) => {
|
|
561
|
-
timelineReadyGeneration++;
|
|
562
|
-
set({ timelineReady: ready });
|
|
563
|
-
},
|
|
564
|
-
requestTimelineReady: (doc) => {
|
|
565
|
-
const generation = ++timelineReadyGeneration;
|
|
566
|
-
if (!doc) return set({ timelineReady: true });
|
|
567
|
-
if (!loadStepDocs.has(doc)) {
|
|
568
|
-
awaitingLoadStep = { doc, generation };
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
settle(doc, generation);
|
|
572
|
-
},
|
|
573
|
-
markPreviewLoadStep: (doc) => {
|
|
574
|
-
loadStepDocs.add(doc);
|
|
575
|
-
if (awaitingLoadStep?.doc !== doc) return;
|
|
576
|
-
const { generation } = awaitingLoadStep;
|
|
577
|
-
awaitingLoadStep = null;
|
|
578
|
-
settle(doc, generation);
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// src/player/store/rangeSelectionSlice.ts
|
|
584
|
-
function createRangeSelectionSlice() {
|
|
585
|
-
return { rangeSelection: null };
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// src/player/store/timelineResetState.ts
|
|
589
|
-
function createTimelineResetState() {
|
|
590
|
-
return {
|
|
591
|
-
isPlaying: false,
|
|
592
|
-
currentTime: 0,
|
|
593
|
-
duration: 0,
|
|
594
|
-
...resetPlaybackReadinessState(),
|
|
595
|
-
beatDragging: false,
|
|
596
|
-
elements: [],
|
|
597
|
-
selectedElementId: null,
|
|
598
|
-
zEditVersion: 0,
|
|
599
|
-
inPoint: null,
|
|
600
|
-
outPoint: null,
|
|
601
|
-
rangeSelection: null,
|
|
602
|
-
activeTool: "select",
|
|
603
|
-
activeKeyframePct: null,
|
|
604
|
-
motionPathArmed: false,
|
|
605
|
-
motionPathCreateAvailable: false,
|
|
606
|
-
selectedKeyframes: /* @__PURE__ */ new Set(),
|
|
607
|
-
// Ephemeral like every other selection here. A range surviving a project
|
|
608
|
-
// switch can match a same-keyed clip in the new project and redirect a
|
|
609
|
-
// paste through `sel.elementKey === paste.elementKey` to a stale t0.
|
|
610
|
-
automationSelection: null,
|
|
611
|
-
expandedClipIds: /* @__PURE__ */ new Set(),
|
|
612
|
-
// Per-composition: ids from comp A match nothing in B, silencing all of it.
|
|
613
|
-
collapsedGroupIds: /* @__PURE__ */ new Set(),
|
|
614
|
-
expandedLaneOwnerIds: /* @__PURE__ */ new Set(),
|
|
615
|
-
focusedEaseSegment: null,
|
|
616
|
-
revealedAudioFxTarget: null,
|
|
617
|
-
selectedElementIds: /* @__PURE__ */ new Set(),
|
|
618
|
-
requestedSeekTime: null,
|
|
619
|
-
lintFindingsByElement: /* @__PURE__ */ new Map(),
|
|
620
|
-
timelineFocus: null,
|
|
621
|
-
keyframeCache: /* @__PURE__ */ new Map(),
|
|
622
|
-
gsapAnimations: /* @__PURE__ */ new Map(),
|
|
623
|
-
beatAnalysis: null,
|
|
624
|
-
beatEdits: null,
|
|
625
|
-
beatUndo: [],
|
|
626
|
-
beatRedo: [],
|
|
627
|
-
beatPersist: null,
|
|
628
|
-
clipManifest: null,
|
|
629
|
-
clipParentMap: /* @__PURE__ */ new Map(),
|
|
630
|
-
domClipChildren: [],
|
|
631
|
-
subCompositionHostState: /* @__PURE__ */ new Map()
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// src/player/store/elementPatchQueue.ts
|
|
636
|
-
var queued = null;
|
|
637
|
-
function queueElementPatch(key, updates) {
|
|
638
|
-
if (!queued) return false;
|
|
639
|
-
queued.set(key, { ...queued.get(key), ...updates });
|
|
640
|
-
return true;
|
|
641
|
-
}
|
|
642
|
-
function collectElementPatches(run) {
|
|
643
|
-
if (queued) {
|
|
644
|
-
run();
|
|
645
|
-
return null;
|
|
646
|
-
}
|
|
647
|
-
const patches = queued = /* @__PURE__ */ new Map();
|
|
648
|
-
try {
|
|
649
|
-
run();
|
|
650
|
-
} finally {
|
|
651
|
-
queued = null;
|
|
652
|
-
}
|
|
653
|
-
return patches;
|
|
654
|
-
}
|
|
655
|
-
function patchElements(elements, patches) {
|
|
656
|
-
return elements.map((el) => {
|
|
657
|
-
const patch = patches.get(el.key ?? el.id);
|
|
658
|
-
return patch ? { ...el, ...patch } : el;
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// src/player/store/playerStore.ts
|
|
663
|
-
function resolveElementSelection(ids, anchor) {
|
|
664
|
-
const selectedElementIds = new Set(ids);
|
|
665
|
-
if (selectedElementIds.size === 0) {
|
|
666
|
-
return { selectedElementIds, selectedElementId: null };
|
|
667
|
-
}
|
|
668
|
-
if (anchor && selectedElementIds.has(anchor)) {
|
|
669
|
-
return { selectedElementIds, selectedElementId: anchor };
|
|
670
|
-
}
|
|
671
|
-
return {
|
|
672
|
-
selectedElementIds,
|
|
673
|
-
selectedElementId: selectedElementIds.values().next().value ?? null
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function selectAroundPlayhead(state, keep) {
|
|
677
|
-
const playhead = state.isPlaying ? liveTime.latest() : state.currentTime;
|
|
678
|
-
const ids = state.elements.filter((el) => keep(el, playhead)).map((el) => el.key ?? el.id);
|
|
679
|
-
state.setSelectedElementId(ids[0] ?? null);
|
|
680
|
-
state.setSelectedElementIds(new Set(ids));
|
|
681
|
-
}
|
|
682
|
-
var usePlayerStore = create((set, get) => ({
|
|
683
|
-
isPlaying: false,
|
|
684
|
-
currentTime: 0,
|
|
685
|
-
duration: 0,
|
|
686
|
-
timelineSessionEpoch: 0,
|
|
687
|
-
timelineProjectId: null,
|
|
688
|
-
beatDragging: false,
|
|
689
|
-
elements: [],
|
|
690
|
-
selectedElementId: null,
|
|
691
|
-
playbackRate: readStudioUiPreferences().playbackRate ?? 1,
|
|
692
|
-
audioMuted: readStudioUiPreferences().audioMuted ?? false,
|
|
693
|
-
audioVolume: readStudioUiPreferences().audioVolume ?? 1,
|
|
694
|
-
loopEnabled: false,
|
|
695
|
-
zoomMode: "fit",
|
|
696
|
-
manualZoomPercent: 100,
|
|
697
|
-
userZoomCount: 0,
|
|
698
|
-
zEditVersion: 0,
|
|
699
|
-
timelinePps: 100,
|
|
700
|
-
timelineFitPps: 100,
|
|
701
|
-
inPoint: null,
|
|
702
|
-
outPoint: null,
|
|
703
|
-
activeTool: "select",
|
|
704
|
-
setActiveTool: (tool) => set({ activeTool: tool }),
|
|
705
|
-
selectLeftward: () => selectAroundPlayhead(get(), (el, t) => el.start < t),
|
|
706
|
-
selectRightward: () => selectAroundPlayhead(get(), (el, t) => el.start + el.duration > t),
|
|
707
|
-
...createKeyframeSlice(set, () => ({
|
|
708
|
-
timelineProjectId: get().timelineProjectId,
|
|
709
|
-
timelineSessionEpoch: get().timelineSessionEpoch
|
|
710
|
-
})),
|
|
711
|
-
...createThumbnailSlice(set),
|
|
712
|
-
...createAutomationSelectionSlice(set),
|
|
713
|
-
...createEditingModeSlice(set),
|
|
714
|
-
...createRangeSelectionSlice(),
|
|
715
|
-
...createPlaybackReadinessSlice(set),
|
|
716
|
-
activeKeyframePct: null,
|
|
717
|
-
setActiveKeyframePct: (pct) => set({ activeKeyframePct: pct }),
|
|
718
|
-
selectedElementIds: /* @__PURE__ */ new Set(),
|
|
719
|
-
setSelection: (ids, anchor) => set(resolveElementSelection(ids, anchor)),
|
|
720
|
-
addSelectedElementId: (id) => set((s) => {
|
|
721
|
-
const next = new Set(s.selectedElementIds);
|
|
722
|
-
next.add(id);
|
|
723
|
-
return resolveElementSelection(next, s.selectedElementId);
|
|
724
|
-
}),
|
|
725
|
-
toggleSelectedElementId: (id) => set((s) => {
|
|
726
|
-
const next = new Set(s.selectedElementIds);
|
|
727
|
-
if (next.has(id)) next.delete(id);
|
|
728
|
-
else next.add(id);
|
|
729
|
-
return resolveElementSelection(next, s.selectedElementId);
|
|
730
|
-
}),
|
|
731
|
-
clearSelection: () => set({ selectedElementId: null, selectedElementIds: /* @__PURE__ */ new Set() }),
|
|
732
|
-
requestedSeekTime: null,
|
|
733
|
-
requestSeek: (time) => set({ requestedSeekTime: time }),
|
|
734
|
-
clearSeekRequest: () => set({ requestedSeekTime: null }),
|
|
735
|
-
playbackRequest: null,
|
|
736
|
-
requestPlayback: (playing, returnTo = null) => set((s) => ({
|
|
737
|
-
playbackRequest: { playing, returnTo, nonce: (s.playbackRequest?.nonce ?? 0) + 1 }
|
|
738
|
-
})),
|
|
739
|
-
clearPlaybackRequest: () => set({ playbackRequest: null }),
|
|
740
|
-
clipRevealRequest: null,
|
|
741
|
-
requestClipReveal: (elementId) => set((s) => ({
|
|
742
|
-
clipRevealRequest: { elementId, nonce: (s.clipRevealRequest?.nonce ?? 0) + 1 }
|
|
743
|
-
})),
|
|
744
|
-
clearClipRevealRequest: () => set({ clipRevealRequest: null }),
|
|
745
|
-
timelineFocus: null,
|
|
746
|
-
timelineFocusNonce: 0,
|
|
747
|
-
requestTimelineFocus: (id) => set((s) => {
|
|
748
|
-
const nonce = s.timelineFocusNonce + 1;
|
|
749
|
-
return {
|
|
750
|
-
timelineFocusNonce: nonce,
|
|
751
|
-
timelineFocus: createTimelineFocusRequest(
|
|
752
|
-
id,
|
|
753
|
-
s.timelineProjectId,
|
|
754
|
-
s.timelineSessionEpoch,
|
|
755
|
-
nonce
|
|
756
|
-
)
|
|
757
|
-
};
|
|
758
|
-
}),
|
|
759
|
-
clearTimelineFocus: (nonce) => set((s) => s.timelineFocus?.nonce === nonce ? { timelineFocus: null } : s),
|
|
760
|
-
lintFindingsByElement: /* @__PURE__ */ new Map(),
|
|
761
|
-
setLintFindingsByElement: (map) => set({ lintFindingsByElement: map }),
|
|
762
|
-
beatAnalysis: null,
|
|
763
|
-
setBeatAnalysis: (analysis) => set({ beatAnalysis: analysis }),
|
|
764
|
-
beatEdits: null,
|
|
765
|
-
setBeatEdits: (edits) => set({ beatEdits: edits }),
|
|
766
|
-
beatUndo: [],
|
|
767
|
-
beatRedo: [],
|
|
768
|
-
beatPersist: null,
|
|
769
|
-
setBeatPersist: (fn) => set({ beatPersist: fn }),
|
|
770
|
-
commitBeatEdits: (next, label) => {
|
|
771
|
-
set((s) => ({
|
|
772
|
-
beatEdits: next,
|
|
773
|
-
beatUndo: [...s.beatUndo, { restore: s.beatEdits, at: Date.now(), label }],
|
|
774
|
-
beatRedo: []
|
|
775
|
-
}));
|
|
776
|
-
get().beatPersist?.();
|
|
777
|
-
},
|
|
778
|
-
undoBeatEdits: () => {
|
|
779
|
-
const s = get();
|
|
780
|
-
const entry = s.beatUndo[s.beatUndo.length - 1];
|
|
781
|
-
if (!entry) return null;
|
|
782
|
-
set({
|
|
783
|
-
beatEdits: entry.restore,
|
|
784
|
-
beatUndo: s.beatUndo.slice(0, -1),
|
|
785
|
-
beatRedo: [...s.beatRedo, { restore: s.beatEdits, at: entry.at, label: entry.label }]
|
|
786
|
-
});
|
|
787
|
-
get().beatPersist?.();
|
|
788
|
-
return entry.label;
|
|
789
|
-
},
|
|
790
|
-
resetBeatHistory: () => set({ beatUndo: [], beatRedo: [] }),
|
|
791
|
-
redoBeatEdits: () => {
|
|
792
|
-
const s = get();
|
|
793
|
-
const entry = s.beatRedo[s.beatRedo.length - 1];
|
|
794
|
-
if (!entry) return null;
|
|
795
|
-
set({
|
|
796
|
-
beatEdits: entry.restore,
|
|
797
|
-
beatRedo: s.beatRedo.slice(0, -1),
|
|
798
|
-
beatUndo: [...s.beatUndo, { restore: s.beatEdits, at: entry.at, label: entry.label }]
|
|
799
|
-
});
|
|
800
|
-
get().beatPersist?.();
|
|
801
|
-
return entry.label;
|
|
802
|
-
},
|
|
803
|
-
clipManifest: null,
|
|
804
|
-
setClipManifest: (clips) => set({ clipManifest: clips }),
|
|
805
|
-
clipParentMap: /* @__PURE__ */ new Map(),
|
|
806
|
-
setClipParentMap: (map) => set({ clipParentMap: map }),
|
|
807
|
-
domClipChildren: [],
|
|
808
|
-
setDomClipChildren: (children) => set({ domClipChildren: children }),
|
|
809
|
-
subCompositionHostState: /* @__PURE__ */ new Map(),
|
|
810
|
-
setSubCompositionHostState: (state) => set({ subCompositionHostState: state }),
|
|
811
|
-
setIsPlaying: (playing) => {
|
|
812
|
-
if (get().isPlaying === playing) return;
|
|
813
|
-
set({ isPlaying: playing });
|
|
814
|
-
},
|
|
815
|
-
setPlaybackRate: (rate) => {
|
|
816
|
-
writeStudioUiPreferences({ playbackRate: rate });
|
|
817
|
-
set({ playbackRate: rate });
|
|
818
|
-
},
|
|
819
|
-
setAudioMuted: (muted) => {
|
|
820
|
-
writeStudioUiPreferences({ audioMuted: muted });
|
|
821
|
-
set({ audioMuted: muted });
|
|
822
|
-
},
|
|
823
|
-
setAudioVolume: (volume) => {
|
|
824
|
-
const nextVolume = Number.isFinite(volume) ? Math.max(0, Math.min(1, volume)) : 1;
|
|
825
|
-
writeStudioUiPreferences({ audioVolume: nextVolume });
|
|
826
|
-
set({ audioVolume: nextVolume });
|
|
827
|
-
},
|
|
828
|
-
setLoopEnabled: (enabled) => set({ loopEnabled: enabled }),
|
|
829
|
-
setZoomMode: (mode) => set({ zoomMode: mode }),
|
|
830
|
-
clearSelectedElementIds: () => set({ selectedElementIds: /* @__PURE__ */ new Set() }),
|
|
831
|
-
setSelectedElementIds: (ids) => set({ selectedElementIds: new Set(ids) }),
|
|
832
|
-
timelineSnapEnabled: readStudioUiPreferences().timelineSnapEnabled ?? true,
|
|
833
|
-
setTimelineSnapEnabled: (enabled) => {
|
|
834
|
-
writeStudioUiPreferences({ timelineSnapEnabled: enabled });
|
|
835
|
-
set({ timelineSnapEnabled: enabled });
|
|
836
|
-
},
|
|
837
|
-
rippleEditEnabled: readStudioUiPreferences().rippleEditEnabled ?? true,
|
|
838
|
-
// default on
|
|
839
|
-
setRippleEditEnabled: (enabled) => {
|
|
840
|
-
writeStudioUiPreferences({ rippleEditEnabled: enabled });
|
|
841
|
-
set({ rippleEditEnabled: enabled });
|
|
842
|
-
},
|
|
843
|
-
timeDisplayMode: readStudioUiPreferences().timeDisplayMode ?? "time",
|
|
844
|
-
setTimeDisplayMode: (mode) => {
|
|
845
|
-
writeStudioUiPreferences({ timeDisplayMode: mode });
|
|
846
|
-
set({ timeDisplayMode: mode });
|
|
847
|
-
},
|
|
848
|
-
pinTimelineZoom: (currentPixelsPerSecond, fitPixelsPerSecond) => set((s) => {
|
|
849
|
-
if (s.zoomMode === "manual") return {};
|
|
850
|
-
const percent = computePinnedZoomPercent(currentPixelsPerSecond, fitPixelsPerSecond);
|
|
851
|
-
writeStudioUiPreferences({
|
|
852
|
-
timelineZoomMode: "manual",
|
|
853
|
-
timelineManualZoomPercent: percent
|
|
854
|
-
});
|
|
855
|
-
return { zoomMode: "manual", manualZoomPercent: percent };
|
|
856
|
-
}),
|
|
857
|
-
setTimelineScale: (pps, fitPps) => {
|
|
858
|
-
const state = get();
|
|
859
|
-
if (state.timelinePps === pps && state.timelineFitPps === fitPps) return;
|
|
860
|
-
set({ timelinePps: pps, timelineFitPps: fitPps });
|
|
861
|
-
},
|
|
862
|
-
setInPoint: (time) => set((state) => {
|
|
863
|
-
const t = time !== null && Number.isFinite(time) ? time : null;
|
|
864
|
-
return {
|
|
865
|
-
inPoint: t,
|
|
866
|
-
outPoint: t !== null && state.outPoint !== null && t >= state.outPoint ? null : state.outPoint,
|
|
867
|
-
// Setting a work-area marker implies the user wants playback bounded by it.
|
|
868
|
-
// Auto-enable loop so the playhead respects the marker instead of running past.
|
|
869
|
-
loopEnabled: t !== null ? true : state.loopEnabled
|
|
870
|
-
};
|
|
871
|
-
}),
|
|
872
|
-
setOutPoint: (time) => set((state) => {
|
|
873
|
-
const t = time !== null && Number.isFinite(time) ? time : null;
|
|
874
|
-
return {
|
|
875
|
-
outPoint: t,
|
|
876
|
-
inPoint: t !== null && state.inPoint !== null && t <= state.inPoint ? null : state.inPoint,
|
|
877
|
-
loopEnabled: t !== null ? true : state.loopEnabled
|
|
878
|
-
};
|
|
879
|
-
}),
|
|
880
|
-
setManualZoomPercent: (percent) => set((state) => ({
|
|
881
|
-
manualZoomPercent: clampTimelineZoomPercent(percent, state.timelineFitPps)
|
|
882
|
-
})),
|
|
883
|
-
bumpZEditVersion: () => set((state) => ({ zEditVersion: state.zEditVersion + 1 })),
|
|
884
|
-
setCurrentTime: (time) => set({ currentTime: Number.isFinite(time) ? time : 0 }),
|
|
885
|
-
setDuration: (duration) => set({ duration: Number.isFinite(duration) ? duration : 0 }),
|
|
886
|
-
setBeatDragging: (dragging) => set({ beatDragging: dragging }),
|
|
887
|
-
setElements: (elements) => set({ elements }),
|
|
888
|
-
// A genuine single selection: always collapse the set to just this element. User
|
|
889
|
-
// intent (timeline click, preview click via applyDomSelection) flows here; DOM sync
|
|
890
|
-
// echoes that must preserve a group go through setSelectionAnchor instead.
|
|
891
|
-
setSelectedElementId: (id, options) => set((s) => {
|
|
892
|
-
const selectedElementIds = nextSelectionSet(s.selectedElementIds, id, options?.preserveSet);
|
|
893
|
-
const revealSurvives = revealTargetsSelection(s.revealedAudioFxTarget, id);
|
|
894
|
-
return id !== s.selectedElementId ? {
|
|
895
|
-
selectedElementId: id,
|
|
896
|
-
selectedElementIds,
|
|
897
|
-
activeKeyframePct: null,
|
|
898
|
-
motionPathArmed: false,
|
|
899
|
-
focusedEaseSegment: null,
|
|
900
|
-
...revealSurvives ? {} : { revealedAudioFxTarget: null }
|
|
901
|
-
} : { selectedElementId: id, selectedElementIds };
|
|
902
|
-
}),
|
|
903
|
-
// Move the anchor within an active multi-selection WITHOUT collapsing it — used by
|
|
904
|
-
// DOM->store sync echoes while a group gesture re-patches the preview. A non-member
|
|
905
|
-
// id is treated as a genuine new single selection.
|
|
906
|
-
setSelectionAnchor: (id) => set((s) => {
|
|
907
|
-
if (id != null && s.selectedElementIds.size > 1 && s.selectedElementIds.has(id)) {
|
|
908
|
-
return {
|
|
909
|
-
selectedElementId: id,
|
|
910
|
-
focusedEaseSegment: id === s.selectedElementId ? s.focusedEaseSegment : null
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
return {
|
|
914
|
-
selectedElementId: id,
|
|
915
|
-
selectedElementIds: id ? /* @__PURE__ */ new Set([id]) : /* @__PURE__ */ new Set(),
|
|
916
|
-
focusedEaseSegment: id === s.selectedElementId ? s.focusedEaseSegment : null
|
|
917
|
-
};
|
|
918
|
-
}),
|
|
919
|
-
updateElement: (elementId, updates) => {
|
|
920
|
-
if (queueElementPatch(elementId, updates)) return;
|
|
921
|
-
set((state) => ({ elements: patchElements(state.elements, /* @__PURE__ */ new Map([[elementId, updates]])) }));
|
|
922
|
-
},
|
|
923
|
-
// UI preferences intentionally survive reset. So do timelineSessionEpoch and
|
|
924
|
-
// focusedEaseRequestNonce: the epoch advances only when project identity
|
|
925
|
-
// changes, while a monotonic nonce prevents collisions with stale consumers.
|
|
926
|
-
beginTimelineSession: (projectId) => set((state) => {
|
|
927
|
-
if (state.timelineProjectId === projectId) return state;
|
|
928
|
-
return {
|
|
929
|
-
...createTimelineResetState(),
|
|
930
|
-
timelineSessionEpoch: state.timelineSessionEpoch + 1,
|
|
931
|
-
timelineProjectId: projectId
|
|
932
|
-
};
|
|
933
|
-
}),
|
|
934
|
-
reset: () => set(createTimelineResetState())
|
|
935
|
-
}));
|
|
936
|
-
attachPlayerStoreDevHandle(usePlayerStore);
|
|
937
|
-
function isPreviewBooted(projectId) {
|
|
938
|
-
const { previewBooted, timelineProjectId } = usePlayerStore.getState();
|
|
939
|
-
return previewBooted && timelineProjectId === projectId;
|
|
940
|
-
}
|
|
941
|
-
function whenPreviewBooted(projectId) {
|
|
942
|
-
const openedFrom = usePlayerStore.getState().timelineProjectId;
|
|
943
|
-
let seen = false;
|
|
944
|
-
const settle = (state) => {
|
|
945
|
-
if (state.timelineProjectId === projectId) {
|
|
946
|
-
seen = true;
|
|
947
|
-
return state.previewBooted ? true : null;
|
|
948
|
-
}
|
|
949
|
-
return seen || state.timelineProjectId !== openedFrom ? false : null;
|
|
950
|
-
};
|
|
951
|
-
return new Promise((resolve) => {
|
|
952
|
-
const now = settle(usePlayerStore.getState());
|
|
953
|
-
if (now !== null) return resolve(now);
|
|
954
|
-
const stop = usePlayerStore.subscribe((state) => {
|
|
955
|
-
const result = settle(state);
|
|
956
|
-
if (result === null) return;
|
|
957
|
-
stop();
|
|
958
|
-
resolve(result);
|
|
959
|
-
});
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
// src/player/sceneSwap.ts
|
|
964
|
-
var SCENES_SWAPPED = "hf-scenes-swapped";
|
|
965
|
-
var SCENE_SWAP_MS = 5e3;
|
|
966
|
-
var PREVIEW_DOCUMENT_LOADED = "hf-preview-document-loaded";
|
|
967
|
-
function announcePreviewDocumentLoaded(iframe) {
|
|
968
|
-
iframe.dispatchEvent(new Event(PREVIEW_DOCUMENT_LOADED));
|
|
969
|
-
}
|
|
970
|
-
function onPreviewDocumentLoaded(iframe, onLoaded) {
|
|
971
|
-
iframe.addEventListener(PREVIEW_DOCUMENT_LOADED, onLoaded);
|
|
972
|
-
return () => iframe.removeEventListener(PREVIEW_DOCUMENT_LOADED, onLoaded);
|
|
973
|
-
}
|
|
974
|
-
function onPreviewContentReplaced(iframe, onReplaced) {
|
|
975
|
-
const stopLoaded = onPreviewDocumentLoaded(iframe, onReplaced);
|
|
976
|
-
iframe.addEventListener(SCENES_SWAPPED, onReplaced);
|
|
977
|
-
return () => {
|
|
978
|
-
stopLoaded();
|
|
979
|
-
iframe.removeEventListener(SCENES_SWAPPED, onReplaced);
|
|
980
|
-
};
|
|
981
|
-
}
|
|
982
|
-
var PREVIEW_PROMOTED = "hf-preview-promoted";
|
|
983
|
-
function announcePreviewPromoted(promotion) {
|
|
984
|
-
promotion.live.ownerDocument.dispatchEvent(
|
|
985
|
-
new CustomEvent(PREVIEW_PROMOTED, { detail: promotion })
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
function onPreviewPromoted(doc, listener) {
|
|
989
|
-
const handle = (event) => listener(event.detail);
|
|
990
|
-
doc.addEventListener(PREVIEW_PROMOTED, handle);
|
|
991
|
-
return () => doc.removeEventListener(PREVIEW_PROMOTED, handle);
|
|
992
|
-
}
|
|
993
|
-
function markScenesStale(iframe, files) {
|
|
994
|
-
const doc = iframe?.contentDocument;
|
|
995
|
-
const meta = doc?.querySelector('meta[name="hf-scene-parts"]');
|
|
996
|
-
if (!doc || !meta) return;
|
|
997
|
-
let parts;
|
|
998
|
-
try {
|
|
999
|
-
parts = JSON.parse(meta.content);
|
|
1000
|
-
} catch {
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
|
-
for (const file of files) {
|
|
1004
|
-
const hosts = doc.querySelectorAll(`[data-composition-file="${CSS.escape(file)}"]`);
|
|
1005
|
-
if (hosts.length === 0 && file.endsWith(".html")) parts.shared = "";
|
|
1006
|
-
for (const host of hosts) {
|
|
1007
|
-
const scene = host.closest("[data-hf-scene]")?.getAttribute("data-hf-scene");
|
|
1008
|
-
if (scene && scene in parts.scenes) parts.scenes[scene] = "";
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
meta.content = JSON.stringify(parts);
|
|
1012
|
-
}
|
|
1013
|
-
function sceneSwapFor(iframe) {
|
|
1014
|
-
const win = iframe.contentWindow;
|
|
1015
|
-
const swap = win?.__hfSwapScenes;
|
|
1016
|
-
if (typeof swap !== "function") return null;
|
|
1017
|
-
return async (url, isCurrent, cancel) => {
|
|
1018
|
-
if (cancel?.aborted) throw cancel.reason;
|
|
1019
|
-
const deadline = new AbortController();
|
|
1020
|
-
const timer = setTimeout(
|
|
1021
|
-
() => deadline.abort(new Error("the preview took too long to swap")),
|
|
1022
|
-
SCENE_SWAP_MS
|
|
1023
|
-
);
|
|
1024
|
-
cancel?.addEventListener("abort", () => deadline.abort(cancel.reason), { once: true });
|
|
1025
|
-
const swapping = (async () => {
|
|
1026
|
-
const response = await studioApiFetch(url, { signal: deadline.signal });
|
|
1027
|
-
if (!response.ok) throw new Error(`preview request failed with ${response.status}`);
|
|
1028
|
-
const html = await response.text();
|
|
1029
|
-
if (!isCurrent()) throw new Error("superseded by a newer reload");
|
|
1030
|
-
await swap.call(win, html, deadline.signal);
|
|
1031
|
-
})();
|
|
1032
|
-
const expired = new Promise(
|
|
1033
|
-
(_resolve, reject) => deadline.signal.addEventListener("abort", () => reject(deadline.signal.reason))
|
|
1034
|
-
);
|
|
1035
|
-
try {
|
|
1036
|
-
await Promise.race([swapping, expired]);
|
|
1037
|
-
} finally {
|
|
1038
|
-
clearTimeout(timer);
|
|
1039
|
-
}
|
|
1040
|
-
iframe.dispatchEvent(new Event(SCENES_SWAPPED));
|
|
1041
|
-
};
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
// src/player/components/Player.tsx
|
|
1045
|
-
import { forwardRef, useEffect as useEffect2, useRef, useState } from "react";
|
|
1046
|
-
import { isLottieAnimationLoaded } from "@hyperframes/core/runtime/lottie-readiness";
|
|
1047
|
-
|
|
1048
|
-
// src/hooks/useMountEffect.ts
|
|
1049
|
-
import { useEffect } from "react";
|
|
1050
|
-
function useMountEffect(effect) {
|
|
1051
|
-
useEffect(effect, []);
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
// src/hooks/previewVariablesStore.ts
|
|
1055
|
-
import { create as create2 } from "zustand";
|
|
1056
|
-
var usePreviewVariablesStore = create2((set) => ({
|
|
1057
|
-
values: null,
|
|
1058
|
-
setValues: (values) => set({ values: values && Object.keys(values).length > 0 ? values : null })
|
|
1059
|
-
}));
|
|
1060
|
-
function applyPreviewVariablesToUrl(url) {
|
|
1061
|
-
const values = usePreviewVariablesStore.getState().values;
|
|
1062
|
-
if (values) {
|
|
1063
|
-
url.searchParams.set("variables", JSON.stringify(values));
|
|
1064
|
-
} else {
|
|
1065
|
-
url.searchParams.delete("variables");
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
// src/player/components/Player.tsx
|
|
1070
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1071
|
-
var playerModule = null;
|
|
1072
|
-
function loadPlayerModule() {
|
|
1073
|
-
playerModule ??= import("@hyperframes/player").catch((err) => {
|
|
1074
|
-
playerModule = null;
|
|
1075
|
-
throw err;
|
|
1076
|
-
});
|
|
1077
|
-
return playerModule;
|
|
1078
|
-
}
|
|
1079
|
-
if (typeof window !== "undefined") void loadPlayerModule().catch(() => {
|
|
1080
|
-
});
|
|
1081
|
-
var MEDIA_HAVE_FUTURE_DATA = 3;
|
|
1082
|
-
var MEDIA_NETWORK_NO_SOURCE = 3;
|
|
1083
|
-
function isRecord3(value) {
|
|
1084
|
-
return typeof value === "object" && value !== null;
|
|
1085
|
-
}
|
|
1086
|
-
function getShaderTransitionLoading(event) {
|
|
1087
|
-
if (!(event instanceof CustomEvent)) return null;
|
|
1088
|
-
const detail = event.detail;
|
|
1089
|
-
if (!isRecord3(detail)) return null;
|
|
1090
|
-
const state = detail.state;
|
|
1091
|
-
if (!isRecord3(state)) return null;
|
|
1092
|
-
return state.loading === true && state.ready !== true;
|
|
1093
|
-
}
|
|
1094
|
-
var COMPOSITION_LOADING_OVERLAY_DELAY_MS = 400;
|
|
1095
|
-
var PREVIEW_BOOT_DEADLINE_MS = 5e3;
|
|
1096
|
-
var DEFAULT_PREVIEW_ERROR = "The composition preview did not become ready.";
|
|
1097
|
-
function shouldShowCompositionLoadingOverlay(compositionLoading) {
|
|
1098
|
-
return compositionLoading;
|
|
1099
|
-
}
|
|
1100
|
-
function readPreviewErrorMessage(event) {
|
|
1101
|
-
if (!(event instanceof CustomEvent) || !isRecord3(event.detail)) return DEFAULT_PREVIEW_ERROR;
|
|
1102
|
-
return typeof event.detail.message === "string" && event.detail.message.trim() ? event.detail.message : DEFAULT_PREVIEW_ERROR;
|
|
1103
|
-
}
|
|
1104
|
-
function enableInteractiveIframe(player) {
|
|
1105
|
-
const root = player.shadowRoot;
|
|
1106
|
-
if (!root) return;
|
|
1107
|
-
const container = root.querySelector(".hfp-container");
|
|
1108
|
-
const iframe = root.querySelector(".hfp-iframe");
|
|
1109
|
-
container?.style.setProperty("pointer-events", "auto");
|
|
1110
|
-
iframe?.style.setProperty("pointer-events", "auto");
|
|
1111
|
-
}
|
|
1112
|
-
function isPreviewMediaElement(el) {
|
|
1113
|
-
const tagName = el.tagName.toLowerCase();
|
|
1114
|
-
return tagName === "video" || tagName === "audio";
|
|
1115
|
-
}
|
|
1116
|
-
function hasUnloadedAssets(iframe, lastResult) {
|
|
1117
|
-
try {
|
|
1118
|
-
const win = iframe.contentWindow;
|
|
1119
|
-
const doc = iframe.contentDocument;
|
|
1120
|
-
if (!win || !doc) return lastResult;
|
|
1121
|
-
for (const el of doc.querySelectorAll("video, audio")) {
|
|
1122
|
-
if (isPreviewMediaElement(el) && !el.error && el.networkState !== MEDIA_NETWORK_NO_SOURCE && el.readyState < MEDIA_HAVE_FUTURE_DATA) {
|
|
1123
|
-
return true;
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
const lotties = win.__hfLottie;
|
|
1127
|
-
if (lotties?.length) {
|
|
1128
|
-
for (const anim of lotties) {
|
|
1129
|
-
if (!isLottieAnimationLoaded(anim)) return true;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
return false;
|
|
1133
|
-
} catch {
|
|
1134
|
-
return lastResult;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
var runtimeBootedIn = (iframe) => iframe.contentWindow?.__playerReady === true;
|
|
1138
|
-
var Player = forwardRef(
|
|
1139
|
-
({
|
|
1140
|
-
projectId,
|
|
1141
|
-
directUrl,
|
|
1142
|
-
onLoad,
|
|
1143
|
-
onReadyToShowChange,
|
|
1144
|
-
onPreviewError,
|
|
1145
|
-
onCompositionLoadingChange,
|
|
1146
|
-
onPainted,
|
|
1147
|
-
portrait,
|
|
1148
|
-
style,
|
|
1149
|
-
suppressLoadingOverlay
|
|
1150
|
-
}, ref) => {
|
|
1151
|
-
const containerRef = useRef(null);
|
|
1152
|
-
const loadCountRef = useRef(0);
|
|
1153
|
-
const assetPollRef = useRef(null);
|
|
1154
|
-
const assetFadeRef = useRef(null);
|
|
1155
|
-
const retryPreviewRef = useRef(null);
|
|
1156
|
-
const loadStartedAtRef = useRef(0);
|
|
1157
|
-
const loadIdRef = useRef(0);
|
|
1158
|
-
const retryCountRef = useRef(0);
|
|
1159
|
-
const onLoadRef = useRef(onLoad);
|
|
1160
|
-
onLoadRef.current = onLoad;
|
|
1161
|
-
const onReadyToShowChangeRef = useRef(onReadyToShowChange);
|
|
1162
|
-
onReadyToShowChangeRef.current = onReadyToShowChange;
|
|
1163
|
-
const onPreviewErrorRef = useRef(onPreviewError);
|
|
1164
|
-
onPreviewErrorRef.current = onPreviewError;
|
|
1165
|
-
const [loaded, setLoaded] = useState(false);
|
|
1166
|
-
const [assetsLoading, setAssetsLoading] = useState(false);
|
|
1167
|
-
const [assetOverlayVisible, setAssetOverlayVisible] = useState(false);
|
|
1168
|
-
const [assetOverlayFading, setAssetOverlayFading] = useState(false);
|
|
1169
|
-
const [assetWaitLong, setAssetWaitLong] = useState(false);
|
|
1170
|
-
const [shaderTransitionLoading, setShaderTransitionLoading] = useState(false);
|
|
1171
|
-
const [compositionLoading, setCompositionLoading] = useState(true);
|
|
1172
|
-
const [painted, setPainted] = useState(false);
|
|
1173
|
-
const [compositionOverlayDeferred, setCompositionOverlayDeferred] = useState(true);
|
|
1174
|
-
const [previewError, setPreviewError] = useState(null);
|
|
1175
|
-
useEffect2(() => {
|
|
1176
|
-
if (!compositionLoading) {
|
|
1177
|
-
setCompositionOverlayDeferred(true);
|
|
1178
|
-
return;
|
|
1179
|
-
}
|
|
1180
|
-
const timer = setTimeout(
|
|
1181
|
-
() => setCompositionOverlayDeferred(false),
|
|
1182
|
-
COMPOSITION_LOADING_OVERLAY_DELAY_MS
|
|
1183
|
-
);
|
|
1184
|
-
return () => clearTimeout(timer);
|
|
1185
|
-
}, [compositionLoading]);
|
|
1186
|
-
useMountEffect(() => {
|
|
1187
|
-
const container = containerRef.current;
|
|
1188
|
-
if (!container) return;
|
|
1189
|
-
const previewSource = directUrl || (projectId ? buildProjectApiPath(projectId, "/preview") : null);
|
|
1190
|
-
if (!previewSource) return;
|
|
1191
|
-
let canceled = false;
|
|
1192
|
-
let cleanup;
|
|
1193
|
-
void loadPlayerModule().then(() => {
|
|
1194
|
-
if (canceled) return;
|
|
1195
|
-
const player = document.createElement("hyperframes-player");
|
|
1196
|
-
const srcUrl = new URL(previewSource, window.location.origin);
|
|
1197
|
-
applyPreviewVariablesToUrl(srcUrl);
|
|
1198
|
-
const src = srcUrl.pathname + srcUrl.search;
|
|
1199
|
-
const retryPreview = () => {
|
|
1200
|
-
retryCountRef.current += 1;
|
|
1201
|
-
const retryUrl = new URL(src, window.location.origin);
|
|
1202
|
-
retryUrl.searchParams.set("_hfStudioRetry", String(retryCountRef.current));
|
|
1203
|
-
setPreviewError(null);
|
|
1204
|
-
setCompositionLoading(true);
|
|
1205
|
-
loadStartedAtRef.current = performance.now();
|
|
1206
|
-
loadIdRef.current += 1;
|
|
1207
|
-
player.setAttribute("src", retryUrl.pathname + retryUrl.search);
|
|
1208
|
-
};
|
|
1209
|
-
retryPreviewRef.current = retryPreview;
|
|
1210
|
-
const iframe = player.iframeElement;
|
|
1211
|
-
const preventToggle = (e) => e.stopImmediatePropagation();
|
|
1212
|
-
const handleShaderTransitionState = (event) => {
|
|
1213
|
-
const loading = getShaderTransitionLoading(event);
|
|
1214
|
-
if (loading !== null) setShaderTransitionLoading(loading);
|
|
1215
|
-
};
|
|
1216
|
-
let loadedDocument = null;
|
|
1217
|
-
const handleReady = () => {
|
|
1218
|
-
setPreviewError(null);
|
|
1219
|
-
setCompositionLoading(false);
|
|
1220
|
-
if (iframe.contentDocument && runtimeBootedIn(iframe)) handleLoad();
|
|
1221
|
-
};
|
|
1222
|
-
const handlePainted = () => {
|
|
1223
|
-
setPainted(true);
|
|
1224
|
-
onPainted?.({ iframe, startedAt: loadStartedAtRef.current, loadId: loadIdRef.current });
|
|
1225
|
-
};
|
|
1226
|
-
const handleError = (event) => {
|
|
1227
|
-
const message = readPreviewErrorMessage(event);
|
|
1228
|
-
onPreviewErrorRef.current?.(message);
|
|
1229
|
-
setPreviewError(message);
|
|
1230
|
-
setCompositionLoading(false);
|
|
1231
|
-
};
|
|
1232
|
-
const handleLoad = () => {
|
|
1233
|
-
const doc = iframe.contentDocument;
|
|
1234
|
-
if (doc && doc === loadedDocument) return;
|
|
1235
|
-
loadedDocument = doc;
|
|
1236
|
-
loadCountRef.current++;
|
|
1237
|
-
setLoaded(true);
|
|
1238
|
-
setPreviewError(null);
|
|
1239
|
-
setShaderTransitionLoading(false);
|
|
1240
|
-
setCompositionLoading(!player.ready);
|
|
1241
|
-
setPainted(Boolean(player.painted));
|
|
1242
|
-
if (loadCountRef.current > 1) {
|
|
1243
|
-
container.classList.remove("preview-revealing");
|
|
1244
|
-
void container.offsetWidth;
|
|
1245
|
-
container.classList.add("preview-revealing");
|
|
1246
|
-
const onEnd = () => container.classList.remove("preview-revealing");
|
|
1247
|
-
container.addEventListener("animationend", onEnd, { once: true });
|
|
1248
|
-
}
|
|
1249
|
-
onLoadRef.current();
|
|
1250
|
-
announcePreviewDocumentLoaded(iframe);
|
|
1251
|
-
if (assetPollRef.current) clearInterval(assetPollRef.current);
|
|
1252
|
-
const isContentRefresh = loadCountRef.current > 1;
|
|
1253
|
-
let lastUnloaded = isContentRefresh ? false : hasUnloadedAssets(iframe, false);
|
|
1254
|
-
if (lastUnloaded) {
|
|
1255
|
-
setAssetsLoading(true);
|
|
1256
|
-
let attempts = 0;
|
|
1257
|
-
assetPollRef.current = setInterval(() => {
|
|
1258
|
-
attempts += 1;
|
|
1259
|
-
lastUnloaded = hasUnloadedAssets(iframe, lastUnloaded);
|
|
1260
|
-
if (!lastUnloaded || attempts > 100) {
|
|
1261
|
-
if (lastUnloaded && attempts > 100) {
|
|
1262
|
-
console.debug(
|
|
1263
|
-
"[studio] asset readiness poll hit the 10s cap \u2014 continuing with unloaded assets"
|
|
1264
|
-
);
|
|
1265
|
-
}
|
|
1266
|
-
if (assetPollRef.current) clearInterval(assetPollRef.current);
|
|
1267
|
-
assetPollRef.current = null;
|
|
1268
|
-
setAssetsLoading(false);
|
|
1269
|
-
}
|
|
1270
|
-
}, 100);
|
|
1271
|
-
} else {
|
|
1272
|
-
setAssetsLoading(false);
|
|
1273
|
-
}
|
|
1274
|
-
};
|
|
1275
|
-
iframe.addEventListener("load", handleLoad);
|
|
1276
|
-
player.addEventListener("click", preventToggle, { capture: true });
|
|
1277
|
-
player.addEventListener("shadertransitionstate", handleShaderTransitionState);
|
|
1278
|
-
player.addEventListener("ready", handleReady);
|
|
1279
|
-
player.addEventListener("painted", handlePainted);
|
|
1280
|
-
player.addEventListener("error", handleError);
|
|
1281
|
-
if (typeof ref === "function") {
|
|
1282
|
-
ref(iframe);
|
|
1283
|
-
} else if (ref) {
|
|
1284
|
-
ref.current = iframe;
|
|
1285
|
-
}
|
|
1286
|
-
player.setAttribute("shader-capture-scale", "1");
|
|
1287
|
-
player.setAttribute("shader-loading", "player");
|
|
1288
|
-
player.setAttribute("low-power-idle", "");
|
|
1289
|
-
player.setAttribute("width", String(portrait ? 1080 : 1920));
|
|
1290
|
-
player.setAttribute("height", String(portrait ? 1920 : 1080));
|
|
1291
|
-
player.style.width = "100%";
|
|
1292
|
-
player.style.height = "100%";
|
|
1293
|
-
player.style.display = "block";
|
|
1294
|
-
player.style.background = "transparent";
|
|
1295
|
-
loadStartedAtRef.current = performance.now();
|
|
1296
|
-
loadIdRef.current += 1;
|
|
1297
|
-
player.setAttribute("src", src);
|
|
1298
|
-
container.appendChild(player);
|
|
1299
|
-
if (player.shadowRoot) {
|
|
1300
|
-
const pasteboardStyle = document.createElement("style");
|
|
1301
|
-
pasteboardStyle.textContent = ".hfp-container{overflow:visible}.hfp-iframe{box-shadow:0 0 0 1px rgba(255,255,255,0.08),0 4px 32px rgba(0,0,0,.7)}";
|
|
1302
|
-
player.shadowRoot.appendChild(pasteboardStyle);
|
|
1303
|
-
}
|
|
1304
|
-
enableInteractiveIframe(player);
|
|
1305
|
-
cleanup = () => {
|
|
1306
|
-
iframe.removeEventListener("load", handleLoad);
|
|
1307
|
-
player.removeEventListener("click", preventToggle, { capture: true });
|
|
1308
|
-
player.removeEventListener("shadertransitionstate", handleShaderTransitionState);
|
|
1309
|
-
player.removeEventListener("ready", handleReady);
|
|
1310
|
-
player.removeEventListener("painted", handlePainted);
|
|
1311
|
-
player.removeEventListener("error", handleError);
|
|
1312
|
-
if (assetPollRef.current) clearInterval(assetPollRef.current);
|
|
1313
|
-
assetPollRef.current = null;
|
|
1314
|
-
player.remove();
|
|
1315
|
-
if (retryPreviewRef.current === retryPreview) retryPreviewRef.current = null;
|
|
1316
|
-
if (typeof ref === "function") {
|
|
1317
|
-
} else if (ref) {
|
|
1318
|
-
const mutableRef = ref;
|
|
1319
|
-
if (mutableRef.current === iframe) {
|
|
1320
|
-
mutableRef.current = null;
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
});
|
|
1325
|
-
return () => {
|
|
1326
|
-
canceled = true;
|
|
1327
|
-
cleanup?.();
|
|
1328
|
-
};
|
|
1329
|
-
});
|
|
1330
|
-
useEffect2(() => {
|
|
1331
|
-
if (!assetsLoading) {
|
|
1332
|
-
setAssetWaitLong(false);
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
const timer = setTimeout(() => setAssetWaitLong(true), 3e3);
|
|
1336
|
-
return () => clearTimeout(timer);
|
|
1337
|
-
}, [assetsLoading]);
|
|
1338
|
-
useEffect2(() => {
|
|
1339
|
-
if (assetFadeRef.current) {
|
|
1340
|
-
clearTimeout(assetFadeRef.current);
|
|
1341
|
-
assetFadeRef.current = null;
|
|
1342
|
-
}
|
|
1343
|
-
if (assetsLoading) {
|
|
1344
|
-
setAssetOverlayVisible(true);
|
|
1345
|
-
setAssetOverlayFading(false);
|
|
1346
|
-
return;
|
|
1347
|
-
}
|
|
1348
|
-
setAssetOverlayFading(true);
|
|
1349
|
-
assetFadeRef.current = setTimeout(() => {
|
|
1350
|
-
setAssetOverlayVisible(false);
|
|
1351
|
-
setAssetOverlayFading(false);
|
|
1352
|
-
assetFadeRef.current = null;
|
|
1353
|
-
}, 240);
|
|
1354
|
-
return () => {
|
|
1355
|
-
if (assetFadeRef.current) {
|
|
1356
|
-
clearTimeout(assetFadeRef.current);
|
|
1357
|
-
assetFadeRef.current = null;
|
|
1358
|
-
}
|
|
1359
|
-
};
|
|
1360
|
-
}, [assetsLoading]);
|
|
1361
|
-
const handleContinueAnyway = () => {
|
|
1362
|
-
if (assetPollRef.current) {
|
|
1363
|
-
clearInterval(assetPollRef.current);
|
|
1364
|
-
assetPollRef.current = null;
|
|
1365
|
-
}
|
|
1366
|
-
setAssetsLoading(false);
|
|
1367
|
-
};
|
|
1368
|
-
const firstFrameShown = loaded && painted && !compositionLoading && !shaderTransitionLoading && !previewError;
|
|
1369
|
-
const readyToShow = firstFrameShown && !assetsLoading;
|
|
1370
|
-
useEffect2(() => {
|
|
1371
|
-
if (firstFrameShown) usePlayerStore.getState().markPreviewBooted();
|
|
1372
|
-
}, [firstFrameShown]);
|
|
1373
|
-
useEffect2(() => {
|
|
1374
|
-
if (!readyToShow) {
|
|
1375
|
-
onReadyToShowChangeRef.current?.(false);
|
|
1376
|
-
return;
|
|
1377
|
-
}
|
|
1378
|
-
let second = 0;
|
|
1379
|
-
const first = requestAnimationFrame(() => {
|
|
1380
|
-
second = requestAnimationFrame(() => onReadyToShowChangeRef.current?.(true));
|
|
1381
|
-
});
|
|
1382
|
-
return () => {
|
|
1383
|
-
cancelAnimationFrame(first);
|
|
1384
|
-
cancelAnimationFrame(second);
|
|
1385
|
-
};
|
|
1386
|
-
}, [readyToShow]);
|
|
1387
|
-
useEffect2(() => {
|
|
1388
|
-
if (previewError) usePlayerStore.getState().markPreviewBooted();
|
|
1389
|
-
}, [previewError]);
|
|
1390
|
-
useEffect2(() => {
|
|
1391
|
-
const timer = setTimeout(
|
|
1392
|
-
() => usePlayerStore.getState().markPreviewBooted(),
|
|
1393
|
-
PREVIEW_BOOT_DEADLINE_MS
|
|
1394
|
-
);
|
|
1395
|
-
return () => clearTimeout(timer);
|
|
1396
|
-
}, [projectId]);
|
|
1397
|
-
const showCompositionOverlay = !suppressLoadingOverlay && !compositionOverlayDeferred && shouldShowCompositionLoadingOverlay(compositionLoading);
|
|
1398
|
-
const showAssetOverlay = assetOverlayVisible && !shaderTransitionLoading && !showCompositionOverlay && !previewError;
|
|
1399
|
-
useEffect2(() => {
|
|
1400
|
-
onCompositionLoadingChange?.(showCompositionOverlay || showAssetOverlay);
|
|
1401
|
-
}, [onCompositionLoadingChange, showCompositionOverlay, showAssetOverlay]);
|
|
1402
|
-
return /* @__PURE__ */ jsxs(
|
|
1403
|
-
"div",
|
|
1404
|
-
{
|
|
1405
|
-
className: "relative w-full h-full max-w-full max-h-full overflow-hidden flex items-center justify-center",
|
|
1406
|
-
style,
|
|
1407
|
-
children: [
|
|
1408
|
-
/* @__PURE__ */ jsx("div", { ref: containerRef, className: "w-full h-full" }),
|
|
1409
|
-
showCompositionOverlay && /* @__PURE__ */ jsx(
|
|
1410
|
-
"div",
|
|
1411
|
-
{
|
|
1412
|
-
className: "absolute inset-0 bg-black flex items-center justify-center z-30 select-none",
|
|
1413
|
-
"data-hyperframes-ignore": "",
|
|
1414
|
-
"data-testid": "composition-loading-overlay",
|
|
1415
|
-
draggable: false,
|
|
1416
|
-
onDragStart: (event) => event.preventDefault(),
|
|
1417
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
1418
|
-
onPointerDown: (event) => event.preventDefault(),
|
|
1419
|
-
children: /* @__PURE__ */ jsx(
|
|
1420
|
-
HyperframesLoader,
|
|
1421
|
-
{
|
|
1422
|
-
title: "Loading composition",
|
|
1423
|
-
detail: "Preparing the Studio preview.",
|
|
1424
|
-
size: 56
|
|
1425
|
-
}
|
|
1426
|
-
)
|
|
1427
|
-
}
|
|
1428
|
-
),
|
|
1429
|
-
showAssetOverlay && /* @__PURE__ */ jsx(
|
|
1430
|
-
"div",
|
|
1431
|
-
{
|
|
1432
|
-
className: "absolute inset-0 bg-black flex items-center justify-center z-20 select-none",
|
|
1433
|
-
"data-hyperframes-ignore": "",
|
|
1434
|
-
draggable: false,
|
|
1435
|
-
style: {
|
|
1436
|
-
opacity: assetOverlayFading ? 0 : 1,
|
|
1437
|
-
pointerEvents: assetOverlayFading ? "none" : "auto",
|
|
1438
|
-
transition: "opacity 180ms ease-in"
|
|
1439
|
-
},
|
|
1440
|
-
onDragStart: (event) => event.preventDefault(),
|
|
1441
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
1442
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
|
|
1443
|
-
/* @__PURE__ */ jsx(
|
|
1444
|
-
HyperframesLoader,
|
|
1445
|
-
{
|
|
1446
|
-
title: "Preparing preview assets",
|
|
1447
|
-
detail: "Waiting for media and motion assets before playback starts.",
|
|
1448
|
-
size: 56
|
|
1449
|
-
}
|
|
1450
|
-
),
|
|
1451
|
-
assetWaitLong && /* @__PURE__ */ jsx(
|
|
1452
|
-
"button",
|
|
1453
|
-
{
|
|
1454
|
-
type: "button",
|
|
1455
|
-
onClick: handleContinueAnyway,
|
|
1456
|
-
className: "px-3 py-1.5 text-[11px] rounded-md border border-neutral-700 text-neutral-300 hover:border-neutral-500 hover:bg-neutral-800 transition-colors",
|
|
1457
|
-
children: "Continue anyway"
|
|
1458
|
-
}
|
|
1459
|
-
)
|
|
1460
|
-
] })
|
|
1461
|
-
}
|
|
1462
|
-
),
|
|
1463
|
-
previewError && /* @__PURE__ */ jsx(
|
|
1464
|
-
"div",
|
|
1465
|
-
{
|
|
1466
|
-
className: "absolute inset-0 z-40 flex items-center justify-center bg-black/90 px-6 text-center",
|
|
1467
|
-
"data-hyperframes-ignore": "",
|
|
1468
|
-
"data-testid": "composition-preview-error",
|
|
1469
|
-
children: /* @__PURE__ */ jsxs("div", { className: "max-w-sm", children: [
|
|
1470
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-white", children: "Preview failed to load" }),
|
|
1471
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-neutral-400", children: previewError }),
|
|
1472
|
-
/* @__PURE__ */ jsx(
|
|
1473
|
-
"button",
|
|
1474
|
-
{
|
|
1475
|
-
type: "button",
|
|
1476
|
-
className: "mt-4 rounded-md bg-white px-3 py-1.5 text-xs font-semibold text-black transition-colors hover:bg-neutral-200",
|
|
1477
|
-
onClick: () => retryPreviewRef.current?.(),
|
|
1478
|
-
children: "Retry preview"
|
|
1479
|
-
}
|
|
1480
|
-
)
|
|
1481
|
-
] })
|
|
1482
|
-
}
|
|
1483
|
-
)
|
|
1484
|
-
]
|
|
1485
|
-
}
|
|
1486
|
-
);
|
|
1487
|
-
}
|
|
1488
|
-
);
|
|
1489
|
-
Player.displayName = "Player";
|
|
1490
|
-
|
|
1491
|
-
export {
|
|
1492
|
-
useMountEffect,
|
|
1493
|
-
usePreviewVariablesStore,
|
|
1494
|
-
applyPreviewVariablesToUrl,
|
|
1495
|
-
PANEL_IDS,
|
|
1496
|
-
PANEL_DEFINITIONS,
|
|
1497
|
-
isPanelId,
|
|
1498
|
-
panelsInZone,
|
|
1499
|
-
DOCK_PANEL_COMPONENT,
|
|
1500
|
-
parseDockLayout,
|
|
1501
|
-
readStudioUiPreferences,
|
|
1502
|
-
writeStudioUiPreferences,
|
|
1503
|
-
STUDIO_PREVIEW_FPS,
|
|
1504
|
-
clampToDuration,
|
|
1505
|
-
formatTime,
|
|
1506
|
-
secondsToFrame,
|
|
1507
|
-
frameToSeconds,
|
|
1508
|
-
stepFrameTime,
|
|
1509
|
-
formatFrameTime,
|
|
1510
|
-
clampTimelineZoomPercent,
|
|
1511
|
-
getTimelineZoomPercent,
|
|
1512
|
-
computePinnedZoomPercent,
|
|
1513
|
-
getTimelinePixelsPerSecond,
|
|
1514
|
-
getNextTimelineZoomPercent,
|
|
1515
|
-
getPinchTimelineZoomPercent,
|
|
1516
|
-
timelineZoomPercentToSlider,
|
|
1517
|
-
timelineSliderToZoomPercent,
|
|
1518
|
-
isRevealedAudioFxRequestCurrent,
|
|
1519
|
-
isFocusedEaseRequestCurrent,
|
|
1520
|
-
effectiveThumbnailMode,
|
|
1521
|
-
thumbnailRevisionOf,
|
|
1522
|
-
createTimelineResetState,
|
|
1523
|
-
collectElementPatches,
|
|
1524
|
-
patchElements,
|
|
1525
|
-
liveTime,
|
|
1526
|
-
usePlayerStore,
|
|
1527
|
-
isPreviewBooted,
|
|
1528
|
-
whenPreviewBooted,
|
|
1529
|
-
announcePreviewDocumentLoaded,
|
|
1530
|
-
onPreviewDocumentLoaded,
|
|
1531
|
-
onPreviewContentReplaced,
|
|
1532
|
-
announcePreviewPromoted,
|
|
1533
|
-
onPreviewPromoted,
|
|
1534
|
-
markScenesStale,
|
|
1535
|
-
sceneSwapFor,
|
|
1536
|
-
Player
|
|
1537
|
-
};
|
|
1538
|
-
//# sourceMappingURL=chunk-NZPJUZKT.js.map
|