hyperframes 0.8.87 → 0.8.88

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.
Files changed (84) hide show
  1. package/dist/{add-U6IYWNEI.js → add-6EIX4VO2.js} +5 -5
  2. package/dist/{asset-IVVTJRJ3.js → asset-BYFQENI4.js} +2 -2
  3. package/dist/{auth-B52RVHDK.js → auth-CNYWEFA6.js} +1 -1
  4. package/dist/{autoUpdate-JE4IONTI.js → autoUpdate-FN4SJBTE.js} +2 -2
  5. package/dist/{backgroundChecks-CGYRZGOR.js → backgroundChecks-ODS4VEB5.js} +3 -3
  6. package/dist/backgroundChecksWorker.js +3 -3
  7. package/dist/{beats-E5V4HEFQ.js → beats-RTVNXBLK.js} +4 -4
  8. package/dist/{benchmark-5OYJMUXY.js → benchmark-KKPDM7PU.js} +5 -5
  9. package/dist/{browser-ZCYC2U3H.js → browser-ADH34IWX.js} +3 -3
  10. package/dist/{catalog-Q4L4P7VV.js → catalog-5NIRSEF7.js} +5 -5
  11. package/dist/{check-HM46YAG7.js → check-PRVHJKEC.js} +9 -9
  12. package/dist/{checkBrowser-GMHXULQC.js → checkBrowser-CY3FMWQV.js} +7 -7
  13. package/dist/{chunk-UUMXWC2H.js → chunk-2KCIKXV3.js} +2 -2
  14. package/dist/{chunk-V3RCZR7L.js → chunk-4ARA5OTM.js} +1 -1
  15. package/dist/{chunk-O24S2D45.js → chunk-AV7ASJOK.js} +1 -1
  16. package/dist/{chunk-GMEL3UDG.js → chunk-BM25TRQX.js} +2 -2
  17. package/dist/{chunk-OAT3NROY.js → chunk-DDXTUSZ3.js} +2 -2
  18. package/dist/{chunk-VP53XFPD.js → chunk-F6D4LJQG.js} +1 -1
  19. package/dist/{chunk-BQ4N7ECC.js → chunk-ICWOWWC6.js} +1 -1
  20. package/dist/{chunk-V5643PWM.js → chunk-Q2FGKCVO.js} +2 -2
  21. package/dist/{chunk-RXHJRTDQ.js → chunk-RIEQ7B3Q.js} +1 -1
  22. package/dist/{chunk-4MLISXWH.js → chunk-RXRF3N5D.js} +1 -1
  23. package/dist/{chunk-NETMPMSJ.js → chunk-UP5KFGFZ.js} +2 -2
  24. package/dist/{chunk-4GPB7TYV.js → chunk-UX3MPYCP.js} +2 -2
  25. package/dist/{chunk-S4NITUIE.js → chunk-VGS3ZUDB.js} +1 -1
  26. package/dist/{chunk-C4LRCQ7O.js → chunk-XDDHE52R.js} +2 -2
  27. package/dist/{chunk-KGEVE5JJ.js → chunk-ZDAF2XYX.js} +2 -2
  28. package/dist/{clean-LG7EU4Z6.js → clean-ILEUS4I4.js} +3 -3
  29. package/dist/cli.js +44 -44
  30. package/dist/{cloud-DQSKLPJH.js → cloud-YKZ6FMFO.js} +4 -4
  31. package/dist/{compare-QOEPDS3E.js → compare-A7HXMQA2.js} +4 -4
  32. package/dist/{component-ZVGX6SCH.js → component-GSYJQJH2.js} +3 -3
  33. package/dist/{compositions-JVJO7CKJ.js → compositions-4K3YFH25.js} +5 -5
  34. package/dist/{delete-573HEO7D.js → delete-5R7CYMLA.js} +2 -2
  35. package/dist/{doctor-MB6A7TN7.js → doctor-HGGU5EPV.js} +3 -3
  36. package/dist/{events-Z6DV7LT7.js → events-CT5MGBWG.js} +3 -3
  37. package/dist/{events-7F6C7O2R.js → events-RQHXK2BA.js} +2 -2
  38. package/dist/{feedback-ELSUXCWM.js → feedback-S5TP76SF.js} +4 -4
  39. package/dist/{figma-4NL4EZCF.js → figma-JVTSWBQC.js} +3 -3
  40. package/dist/fontLocalizeCli.js +1 -1
  41. package/dist/{get-4W2IN7H3.js → get-B6QNBIOY.js} +2 -2
  42. package/dist/{grade-compare-744LENMN.js → grade-compare-53VJQ6AR.js} +4 -4
  43. package/dist/{help-VET2A2JX.js → help-74I7OBNZ.js} +1 -1
  44. package/dist/{history-BWJH4567.js → history-JAICBG5J.js} +5 -5
  45. package/dist/hyperframes-player.global.js +1 -1
  46. package/dist/{info-TZZU5K44.js → info-DPLY233F.js} +5 -5
  47. package/dist/{init-5QPBGFAP.js → init-GH473WVQ.js} +6 -6
  48. package/dist/{inspect-ZKM46DT2.js → inspect-ALZBOAVC.js} +6 -6
  49. package/dist/{keyframes-L4PTFVRB.js → keyframes-3IHD4566.js} +5 -5
  50. package/dist/{layout-RCQKNYDP.js → layout-DIE6IDNL.js} +6 -6
  51. package/dist/{lint-FDUB6APN.js → lint-BK7RM2VI.js} +6 -6
  52. package/dist/{list-D6NIQOEY.js → list-IETRGPUL.js} +2 -2
  53. package/dist/{login-M6AWHM6U.js → login-6MOHVUEO.js} +4 -4
  54. package/dist/{media-treatment-MRNN2DOS.js → media-treatment-GLTDA25U.js} +5 -5
  55. package/dist/{normalize-audio-WB76C7OQ.js → normalize-audio-225AHD54.js} +4 -4
  56. package/dist/{play-N5FZSNGF.js → play-N2G5Z7OL.js} +4 -4
  57. package/dist/{present-N24VMIWP.js → present-TVY4QRSP.js} +4 -4
  58. package/dist/{preview-RO3INI3V.js → preview-H5D4G6V6.js} +5 -5
  59. package/dist/{render-FQ7VV2TU.js → render-JDBG7432.js} +5 -5
  60. package/dist/{render-FULEBKUN.js → render-LDKZKOVA.js} +5 -5
  61. package/dist/{skills-JPRPPT3N.js → skills-QWPGK2MN.js} +5 -5
  62. package/dist/{skillsUpdateCheck-PPLBLSII.js → skillsUpdateCheck-JY23Q7EF.js} +3 -3
  63. package/dist/{snapshot-HBS2KVJV.js → snapshot-HCLMYOWI.js} +4 -4
  64. package/dist/studio/assets/{hyperframes-player-CtNVImMi.js → hyperframes-player-w3Bbv0kd.js} +1 -1
  65. package/dist/studio/assets/{index-B_MF86RE.js → index-B6PGJTzp.js} +1 -1
  66. package/dist/studio/assets/{index-DZKcDAtf.js → index-DE6cZYR5.js} +175 -175
  67. package/dist/studio/assets/{index-DJ-Ol7YS.js → index-DldknZPp.js} +1 -1
  68. package/dist/studio/{chunk-7PLTC6SV.js → chunk-KU4F7QZ3.js} +9 -1
  69. package/dist/studio/chunk-KU4F7QZ3.js.map +1 -0
  70. package/dist/studio/index.d.ts +3 -0
  71. package/dist/studio/index.html +1 -1
  72. package/dist/studio/index.js +164 -92
  73. package/dist/studio/index.js.map +1 -1
  74. package/dist/studio/player.js +1 -1
  75. package/dist/{studioServer-HIKBLJCQ.js → studioServer-LZDGVKYT.js} +4 -4
  76. package/dist/{telemetry-ZJ6VMRWN.js → telemetry-Z3RLGWGK.js} +3 -3
  77. package/dist/{timeline-NMCFP4IO.js → timeline-WOKBCYLM.js} +5 -5
  78. package/dist/{tokens-ILHCMG2C.js → tokens-RTP2IROL.js} +2 -2
  79. package/dist/{transcribe-TC7XR5IS.js → transcribe-ASVWZ3GP.js} +3 -3
  80. package/dist/{updateCheck-D7C3KAJT.js → updateCheck-5LM5GJCF.js} +2 -2
  81. package/dist/{upgrade-ZGAFWJLS.js → upgrade-YWWAFHLF.js} +2 -2
  82. package/dist/{validate-T243OVX2.js → validate-EWNJ4VOI.js} +6 -6
  83. package/package.json +1 -1
  84. package/dist/studio/chunk-7PLTC6SV.js.map +0 -1
@@ -66,7 +66,7 @@ import {
66
66
  whenPreviewBooted,
67
67
  wrapTimeline,
68
68
  writeStudioUiPreferences
69
- } from "./chunk-7PLTC6SV.js";
69
+ } from "./chunk-KU4F7QZ3.js";
70
70
  import {
71
71
  Button,
72
72
  ContextMenu,
@@ -600,6 +600,8 @@ var DEFAULT_SHORTCUT_SECTIONS = [
600
600
  { key: "\u2318X", label: "Cut element" },
601
601
  { key: hintKey(STUDIO_PLAIN_KEYS.split), label: "Split clip at playhead" },
602
602
  { key: "\u21E7Click", label: "Razor tool: split all tracks" },
603
+ { key: "[", label: "Select clips starting before the playhead" },
604
+ { key: "]", label: "Select clips starting at or after the playhead" },
603
605
  { key: "\u2318G", label: "Group elements" },
604
606
  { key: "\u2318\u21E7G", label: "Ungroup" },
605
607
  { key: "Del", label: "Delete selected element (no keyframe selected)" }
@@ -10657,6 +10659,17 @@ function useTimelineLabelColumn(animationsByElement, elements) {
10657
10659
  return { labelMode, contentOrigin };
10658
10660
  }
10659
10661
 
10662
+ // src/player/components/useTimelineKeyframeData.ts
10663
+ var HIDDEN = {
10664
+ gsapAnimations: /* @__PURE__ */ new Map(),
10665
+ keyframeCache: /* @__PURE__ */ new Map()
10666
+ };
10667
+ function useTimelineKeyframeData(showKeyframes) {
10668
+ const gsapAnimations = usePlayerStore((s) => s.gsapAnimations);
10669
+ const keyframeCache = usePlayerStore((s) => s.keyframeCache);
10670
+ return showKeyframes ? { gsapAnimations, keyframeCache } : HIDDEN;
10671
+ }
10672
+
10660
10673
  // src/player/components/useTimelineScrollViewport.ts
10661
10674
  import { useCallback as useCallback14, useEffect as useEffect17, useRef as useRef19, useState as useState10 } from "react";
10662
10675
 
@@ -12743,6 +12756,7 @@ function useTimelineProviderState({
12743
12756
  canPasteClip,
12744
12757
  theme: themeOverrides,
12745
12758
  showAudioEffects = true,
12759
+ showKeyframes = true,
12746
12760
  sessionEpoch = 0,
12747
12761
  previewIframeRef,
12748
12762
  onZIndexReorder
@@ -12779,8 +12793,9 @@ function useTimelineProviderState({
12779
12793
  const selectedElementId = usePlayerStore((s) => s.selectedElementId);
12780
12794
  const selectedElementIds = usePlayerStore((s) => s.selectedElementIds);
12781
12795
  const focusedEaseSegment = usePlayerStore((s) => s.focusedEaseSegment);
12782
- const gsapAnimations = usePlayerStore((s) => s.gsapAnimations);
12783
- const { labelMode, contentOrigin } = useTimelineLabelColumn(gsapAnimations, timelineElements);
12796
+ const { gsapAnimations, keyframeCache } = useTimelineKeyframeData(showKeyframes);
12797
+ const namedAnimations = usePlayerStore((s) => s.gsapAnimations);
12798
+ const { labelMode, contentOrigin } = useTimelineLabelColumn(namedAnimations, timelineElements);
12784
12799
  const setSelectedElementId = usePlayerStore((s) => s.setSelectedElementId);
12785
12800
  const currentTime = usePlayerStore((s) => s.currentTime);
12786
12801
  const beatDragging = usePlayerStore((s) => s.beatDragging);
@@ -12805,7 +12820,6 @@ function useTimelineProviderState({
12805
12820
  () => getEffectiveTimelineDuration(duration, timelineElements),
12806
12821
  [duration, timelineElements]
12807
12822
  );
12808
- const keyframeCache = usePlayerStore((s) => s.keyframeCache);
12809
12823
  useAutoExpandKeyframedClips(gsapAnimations);
12810
12824
  const {
12811
12825
  tracks,
@@ -79389,6 +79403,13 @@ function dispatchPlainKey(event, key2, cb) {
79389
79403
  usePlayerStore.getState().setActiveTool("select");
79390
79404
  return;
79391
79405
  }
79406
+ if ((key2 === "[" || key2 === "]") && !event.shiftKey && !event.altKey) {
79407
+ event.preventDefault();
79408
+ const store = usePlayerStore.getState();
79409
+ if (key2 === "[") store.selectLeftward();
79410
+ else store.selectRightward();
79411
+ return;
79412
+ }
79392
79413
  if (key2 === "a" && !event.shiftKey && !event.altKey) {
79393
79414
  const { activeTool, setActiveTool } = usePlayerStore.getState();
79394
79415
  if (activeTool === "razor") {
@@ -90149,8 +90170,82 @@ function TimelineHistoryButtons(props) {
90149
90170
  ] });
90150
90171
  }
90151
90172
 
90173
+ // src/components/TimelineToolPicker.tsx
90174
+ import { ArrowLineLeft, ArrowLineRight, CaretDown } from "@phosphor-icons/react";
90175
+ import { jsx as jsx225, jsxs as jsxs179 } from "react/jsx-runtime";
90176
+ function SelectIcon() {
90177
+ return /* @__PURE__ */ jsx225("svg", { width: "16", height: "16", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx225("path", { d: "M2 0.5L10 6L6.5 6.5L8.5 11L6.5 11.5L4.5 7L2 9Z" }) });
90178
+ }
90179
+ function TimelineToolPicker() {
90180
+ const activeTool = usePlayerStore((s) => s.activeTool);
90181
+ const store = () => usePlayerStore.getState();
90182
+ const rows = [
90183
+ {
90184
+ label: "Select",
90185
+ shortcut: "V",
90186
+ icon: /* @__PURE__ */ jsx225(SelectIcon, {}),
90187
+ active: activeTool === "select",
90188
+ run: () => store().setActiveTool("select")
90189
+ },
90190
+ {
90191
+ label: "Split",
90192
+ shortcut: "B",
90193
+ icon: /* @__PURE__ */ jsx225(Scissors, { size: 16 }),
90194
+ active: activeTool === "razor",
90195
+ run: () => store().setActiveTool("razor")
90196
+ },
90197
+ {
90198
+ label: "Select leftward",
90199
+ shortcut: "[",
90200
+ icon: /* @__PURE__ */ jsx225(ArrowLineLeft, { size: 16, "aria-hidden": "true" }),
90201
+ active: false,
90202
+ run: () => store().selectLeftward()
90203
+ },
90204
+ {
90205
+ label: "Select rightward",
90206
+ shortcut: "]",
90207
+ icon: /* @__PURE__ */ jsx225(ArrowLineRight, { size: 16, "aria-hidden": "true" }),
90208
+ active: false,
90209
+ run: () => store().selectRightward()
90210
+ }
90211
+ ];
90212
+ const current = rows.find((row) => row.active) ?? rows[0];
90213
+ return /* @__PURE__ */ jsx225(
90214
+ Menu,
90215
+ {
90216
+ "aria-label": "Timeline tools",
90217
+ trigger: /* @__PURE__ */ jsxs179(
90218
+ "button",
90219
+ {
90220
+ type: "button",
90221
+ "aria-label": `Timeline tool: ${current.label}`,
90222
+ className: cn(flatIdle, "gap-0.5"),
90223
+ children: [
90224
+ current.icon,
90225
+ /* @__PURE__ */ jsx225(CaretDown, { size: 10, weight: "bold", "aria-hidden": "true" })
90226
+ ]
90227
+ }
90228
+ ),
90229
+ children: rows.map((row) => /* @__PURE__ */ jsx225(
90230
+ MenuItem,
90231
+ {
90232
+ shortcut: row.shortcut,
90233
+ onClick: row.run,
90234
+ "data-active": row.active || void 0,
90235
+ className: row.active ? "bg-neutral-800 text-white" : void 0,
90236
+ children: /* @__PURE__ */ jsxs179("span", { className: "flex items-center gap-2", children: [
90237
+ row.icon,
90238
+ row.label
90239
+ ] })
90240
+ },
90241
+ row.label
90242
+ ))
90243
+ }
90244
+ );
90245
+ }
90246
+
90152
90247
  // src/components/TimelineToolbar.tsx
90153
- import { Fragment as Fragment63, jsx as jsx225, jsxs as jsxs179 } from "react/jsx-runtime";
90248
+ import { Fragment as Fragment63, jsx as jsx226, jsxs as jsxs180 } from "react/jsx-runtime";
90154
90249
  var NO_KEYFRAME_TOGGLE = {
90155
90250
  state: "none",
90156
90251
  isMotionPath: false,
@@ -90212,8 +90307,6 @@ function TimelineToolbar({
90212
90307
  showAddBeat = true,
90213
90308
  showKeyframes = true
90214
90309
  }) {
90215
- const activeTool = usePlayerStore((s) => s.activeTool);
90216
- const setActiveTool = usePlayerStore((s) => s.setActiveTool);
90217
90310
  const timelineSnapEnabled = usePlayerStore((s) => s.timelineSnapEnabled);
90218
90311
  const setTimelineSnapEnabled = usePlayerStore((s) => s.setTimelineSnapEnabled);
90219
90312
  const rippleEditEnabled = usePlayerStore((s) => s.rippleEditEnabled);
@@ -90268,33 +90361,12 @@ function TimelineToolbar({
90268
90361
  return (
90269
90362
  // The "TIMELINE" label is dropped for CapCut-like density — the pane's
90270
90363
  // position (tracks right below) makes it self-evident.
90271
- /* @__PURE__ */ jsx225("div", { className: "border-b border-neutral-800/60", children: /* @__PURE__ */ jsxs179("div", { className: "flex items-center justify-between px-2 py-0.5", children: [
90272
- /* @__PURE__ */ jsxs179("div", { className: "flex items-center gap-0.5", children: [
90273
- /* @__PURE__ */ jsx225(TimelineHistoryButtons, { ...history2 }),
90274
- /* @__PURE__ */ jsx225(Tooltip, { label: "Selection tool (V)", children: /* @__PURE__ */ jsx225(
90275
- "button",
90276
- {
90277
- type: "button",
90278
- onClick: () => setActiveTool("select"),
90279
- "aria-label": "Selection tool",
90280
- "aria-pressed": activeTool === "select",
90281
- className: activeTool === "select" ? flatActive : flatIdle,
90282
- children: /* @__PURE__ */ jsx225("svg", { width: "16", height: "16", viewBox: "0 0 12 12", fill: "currentColor", children: /* @__PURE__ */ jsx225("path", { d: "M2 0.5L10 6L6.5 6.5L8.5 11L6.5 11.5L4.5 7L2 9Z" }) })
90283
- }
90284
- ) }),
90285
- /* @__PURE__ */ jsx225(Tooltip, { label: "Razor tool (B) \u2014 Shift+click splits all tracks", children: /* @__PURE__ */ jsx225(
90286
- "button",
90287
- {
90288
- type: "button",
90289
- onClick: () => setActiveTool("razor"),
90290
- "aria-label": "Razor tool",
90291
- "aria-pressed": activeTool === "razor",
90292
- className: activeTool === "razor" ? flatActive : flatIdle,
90293
- children: /* @__PURE__ */ jsx225(Scissors, { size: 16 })
90294
- }
90295
- ) }),
90296
- /* @__PURE__ */ jsx225("div", { "aria-hidden": "true", className: "mx-1 h-4 w-px bg-neutral-800" }),
90297
- /* @__PURE__ */ jsx225(Tooltip, { label: timelineSnapEnabled ? "Snapping on (N)" : "Snapping off (N)", children: /* @__PURE__ */ jsx225(
90364
+ /* @__PURE__ */ jsx226("div", { className: "border-b border-neutral-800/60", children: /* @__PURE__ */ jsxs180("div", { className: "flex items-center justify-between px-2 py-0.5", children: [
90365
+ /* @__PURE__ */ jsxs180("div", { className: "flex items-center gap-0.5", children: [
90366
+ /* @__PURE__ */ jsx226(TimelineHistoryButtons, { ...history2 }),
90367
+ /* @__PURE__ */ jsx226(TimelineToolPicker, {}),
90368
+ /* @__PURE__ */ jsx226("div", { "aria-hidden": "true", className: "mx-1 h-4 w-px bg-neutral-800" }),
90369
+ /* @__PURE__ */ jsx226(Tooltip, { label: timelineSnapEnabled ? "Snapping on (N)" : "Snapping off (N)", children: /* @__PURE__ */ jsx226(
90298
90370
  "button",
90299
90371
  {
90300
90372
  type: "button",
@@ -90302,14 +90374,14 @@ function TimelineToolbar({
90302
90374
  "aria-label": "Toggle timeline snapping",
90303
90375
  "aria-pressed": timelineSnapEnabled,
90304
90376
  className: timelineSnapEnabled ? flatActive : flatIdle,
90305
- children: /* @__PURE__ */ jsx225(Magnet, { size: 16, weight: "bold", "aria-hidden": "true" })
90377
+ children: /* @__PURE__ */ jsx226(Magnet, { size: 16, weight: "bold", "aria-hidden": "true" })
90306
90378
  }
90307
90379
  ) }),
90308
- /* @__PURE__ */ jsx225(
90380
+ /* @__PURE__ */ jsx226(
90309
90381
  Tooltip,
90310
90382
  {
90311
90383
  label: rippleEditEnabled ? "Ripple on \u2014 keeps the main track gapless" : "Ripple off \u2014 deleting a main-track clip leaves a gap",
90312
- children: /* @__PURE__ */ jsx225(
90384
+ children: /* @__PURE__ */ jsx226(
90313
90385
  "button",
90314
90386
  {
90315
90387
  type: "button",
@@ -90317,12 +90389,12 @@ function TimelineToolbar({
90317
90389
  "aria-label": "Toggle ripple edit",
90318
90390
  "aria-pressed": rippleEditEnabled,
90319
90391
  className: rippleEditEnabled ? flatActive : flatIdle,
90320
- children: /* @__PURE__ */ jsx225(RippleEditIcon, { size: 16 })
90392
+ children: /* @__PURE__ */ jsx226(RippleEditIcon, { size: 16 })
90321
90393
  }
90322
90394
  )
90323
90395
  }
90324
90396
  ),
90325
- projectHasAudio && /* @__PURE__ */ jsx225(Tooltip, { label: audioMetersVisible ? "Hide audio meters" : "Show audio meters", children: /* @__PURE__ */ jsx225(
90397
+ projectHasAudio && /* @__PURE__ */ jsx226(Tooltip, { label: audioMetersVisible ? "Hide audio meters" : "Show audio meters", children: /* @__PURE__ */ jsx226(
90326
90398
  "button",
90327
90399
  {
90328
90400
  type: "button",
@@ -90330,15 +90402,15 @@ function TimelineToolbar({
90330
90402
  "aria-label": "Toggle audio meters",
90331
90403
  "aria-pressed": audioMetersVisible,
90332
90404
  className: audioMetersVisible ? flatActive : flatIdle,
90333
- children: /* @__PURE__ */ jsx225(AudioMetersIcon, { size: 16 })
90405
+ children: /* @__PURE__ */ jsx226(AudioMetersIcon, { size: 16 })
90334
90406
  }
90335
90407
  ) }),
90336
- showKeyframes && /* @__PURE__ */ jsxs179(Fragment63, { children: [
90337
- /* @__PURE__ */ jsx225(
90408
+ showKeyframes && /* @__PURE__ */ jsxs180(Fragment63, { children: [
90409
+ /* @__PURE__ */ jsx226(
90338
90410
  Tooltip,
90339
90411
  {
90340
90412
  label: keyframePathEndpoint ? "Motion path endpoints cannot be removed" : !onToggleKeyframe ? "Select an animated element to add keyframes" : keyframeIsMotionPath ? keyframeWillExtend ? "Extend motion path to playhead (K)" : keyframeState === "active" ? "Remove waypoint from motion path (K)" : "Add waypoint to motion path (K)" : keyframeState === "active" ? "Remove keyframe at playhead (K)" : keyframeState === "inactive" ? keyframeWillExtend ? "Add keyframe at playhead, extends animation (K)" : "Add keyframe at playhead (K)" : "Add keyframe (K)",
90341
- children: /* @__PURE__ */ jsx225(
90413
+ children: /* @__PURE__ */ jsx226(
90342
90414
  "button",
90343
90415
  {
90344
90416
  type: "button",
@@ -90346,7 +90418,7 @@ function TimelineToolbar({
90346
90418
  onClick: onToggleKeyframe,
90347
90419
  "aria-label": keyframePathEndpoint ? "Motion path endpoint" : keyframeIsMotionPath ? keyframeState === "active" ? "Remove motion path waypoint" : keyframeWillExtend ? "Extend motion path to playhead" : "Add motion path waypoint" : keyframeState === "active" ? "Remove keyframe at playhead" : "Add keyframe at playhead",
90348
90420
  className: !onToggleKeyframe ? flatDisabled : `${flatBtn} active:scale-[0.98] hover:bg-white/6 ${keyframeState === "active" ? "text-studio-accent" : keyframeState === "inactive" ? "text-neutral-400 hover:text-studio-accent" : "text-neutral-600 hover:text-neutral-400"}`,
90349
- children: /* @__PURE__ */ jsx225("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "currentColor", children: keyframeState === "active" ? /* @__PURE__ */ jsx225("path", { d: "M5 0.5L9.5 5L5 9.5L0.5 5Z" }) : /* @__PURE__ */ jsx225(
90421
+ children: /* @__PURE__ */ jsx226("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "currentColor", children: keyframeState === "active" ? /* @__PURE__ */ jsx226("path", { d: "M5 0.5L9.5 5L5 9.5L0.5 5Z" }) : /* @__PURE__ */ jsx226(
90350
90422
  "path",
90351
90423
  {
90352
90424
  d: "M5 1.2L8.8 5L5 8.8L1.2 5Z",
@@ -90359,11 +90431,11 @@ function TimelineToolbar({
90359
90431
  )
90360
90432
  }
90361
90433
  ),
90362
- /* @__PURE__ */ jsx225(
90434
+ /* @__PURE__ */ jsx226(
90363
90435
  Tooltip,
90364
90436
  {
90365
90437
  label: autoKeyframeEnabled ? "Auto-record manual edits as keyframes (click to turn off)" : "Manual edits will not be recorded as keyframes (click to turn on)",
90366
- children: /* @__PURE__ */ jsx225(
90438
+ children: /* @__PURE__ */ jsx226(
90367
90439
  "button",
90368
90440
  {
90369
90441
  type: "button",
@@ -90371,9 +90443,9 @@ function TimelineToolbar({
90371
90443
  "aria-label": "Auto-record manual edits as keyframes",
90372
90444
  "aria-pressed": autoKeyframeEnabled,
90373
90445
  className: `${flatBtn} active:scale-[0.98] hover:bg-white/6 ${autoKeyframeEnabled ? "text-red-400 hover:text-red-300" : "text-neutral-600 hover:text-neutral-400"}`,
90374
- children: /* @__PURE__ */ jsxs179("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "none", children: [
90375
- /* @__PURE__ */ jsx225("path", { d: "M5 0.7L9.3 5L5 9.3L0.7 5Z", stroke: "currentColor", strokeWidth: "1" }),
90376
- /* @__PURE__ */ jsx225(
90446
+ children: /* @__PURE__ */ jsxs180("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "none", children: [
90447
+ /* @__PURE__ */ jsx226("path", { d: "M5 0.7L9.3 5L5 9.3L0.7 5Z", stroke: "currentColor", strokeWidth: "1" }),
90448
+ /* @__PURE__ */ jsx226(
90377
90449
  "circle",
90378
90450
  {
90379
90451
  cx: "5",
@@ -90394,11 +90466,11 @@ function TimelineToolbar({
90394
90466
  const el = selectedElementId ? elements.find((e) => (e.key ?? e.id) === selectedElementId) : null;
90395
90467
  const splittable = el != null && canSplitElement(el);
90396
90468
  const canSplit = splittable && currentTime > el.start && currentTime < el.start + el.duration;
90397
- return /* @__PURE__ */ jsx225(
90469
+ return /* @__PURE__ */ jsx226(
90398
90470
  Tooltip,
90399
90471
  {
90400
90472
  label: canSplit ? "Split at playhead (S)" : splittable ? "Move the playhead inside the clip to split" : "Select a clip to split",
90401
- children: /* @__PURE__ */ jsx225(
90473
+ children: /* @__PURE__ */ jsx226(
90402
90474
  "button",
90403
90475
  {
90404
90476
  type: "button",
@@ -90408,7 +90480,7 @@ function TimelineToolbar({
90408
90480
  if (canSplit && el) onSplitElement(el, currentTime);
90409
90481
  },
90410
90482
  className: canSplit ? flatIdle : flatDisabled,
90411
- children: /* @__PURE__ */ jsxs179(
90483
+ children: /* @__PURE__ */ jsxs180(
90412
90484
  "svg",
90413
90485
  {
90414
90486
  width: "16",
@@ -90421,8 +90493,8 @@ function TimelineToolbar({
90421
90493
  strokeLinejoin: "round",
90422
90494
  "aria-hidden": "true",
90423
90495
  children: [
90424
- /* @__PURE__ */ jsx225("path", { d: "M5 3 L7 3 L7 13 L5 13" }),
90425
- /* @__PURE__ */ jsx225("path", { d: "M11 3 L9 3 L9 13 L11 13" })
90496
+ /* @__PURE__ */ jsx226("path", { d: "M5 3 L7 3 L7 13 L5 13" }),
90497
+ /* @__PURE__ */ jsx226("path", { d: "M11 3 L9 3 L9 13 L11 13" })
90426
90498
  ]
90427
90499
  }
90428
90500
  )
@@ -90434,11 +90506,11 @@ function TimelineToolbar({
90434
90506
  (() => {
90435
90507
  if (!showAddBeat) return null;
90436
90508
  const canAdd = beatAnalysisReady && canAddBeatAt(currentTime);
90437
- return /* @__PURE__ */ jsx225(
90509
+ return /* @__PURE__ */ jsx226(
90438
90510
  Tooltip,
90439
90511
  {
90440
90512
  label: !beatAnalysisReady ? "Add a music track with beat analysis to place beats" : canAdd ? "Add beat at playhead" : "A beat already exists at the playhead",
90441
- children: /* @__PURE__ */ jsx225(
90513
+ children: /* @__PURE__ */ jsx226(
90442
90514
  "button",
90443
90515
  {
90444
90516
  type: "button",
@@ -90448,7 +90520,7 @@ function TimelineToolbar({
90448
90520
  if (canAdd) addBeatAtCompositionTime(currentTime);
90449
90521
  },
90450
90522
  className: canAdd ? `${flatBtn} text-neutral-400 hover:bg-white/6 hover:text-[#22c55e] active:scale-[0.98]` : flatDisabled,
90451
- children: /* @__PURE__ */ jsx225("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx225(
90523
+ children: /* @__PURE__ */ jsx226("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx226(
90452
90524
  "path",
90453
90525
  {
90454
90526
  d: "M21 10C21 12.2091 16.9706 14 12 14M21 10C21 7.79086 16.9706 6 12 6C7.02944 6 3 7.79086 3 10M21 10V16C21 18.2091 16.9706 20 12 20M12 14C7.02944 14 3 12.2091 3 10M12 14V20M3 10V16C3 18.2091 7.02944 20 12 20M7 19.3264V13.3264M17 19.3264V13.3264M12 10L20 4",
@@ -90464,12 +90536,12 @@ function TimelineToolbar({
90464
90536
  );
90465
90537
  })()
90466
90538
  ] }),
90467
- /* @__PURE__ */ jsxs179("div", { className: "flex items-center gap-0.5", children: [
90468
- /* @__PURE__ */ jsx225(
90539
+ /* @__PURE__ */ jsxs180("div", { className: "flex items-center gap-0.5", children: [
90540
+ /* @__PURE__ */ jsx226(
90469
90541
  Tooltip,
90470
90542
  {
90471
90543
  label: thumbnailsVisible ? "Hide thumbnails \u2014 labels only" : "Show thumbnails \u2014 posters stay visible; richer previews appear on interaction",
90472
- children: /* @__PURE__ */ jsx225(
90544
+ children: /* @__PURE__ */ jsx226(
90473
90545
  "button",
90474
90546
  {
90475
90547
  type: "button",
@@ -90477,12 +90549,12 @@ function TimelineToolbar({
90477
90549
  "aria-pressed": thumbnailsVisible,
90478
90550
  onClick: () => setThumbnailMode(thumbnailsVisible ? "hidden" : "adaptive"),
90479
90551
  className: `h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${thumbnailsVisible ? "bg-studio-accent/10 text-studio-accent" : "text-neutral-400 hover:bg-white/6 hover:text-neutral-200"}`,
90480
- children: /* @__PURE__ */ jsx225(Image3, { size: 16, "aria-hidden": "true" })
90552
+ children: /* @__PURE__ */ jsx226(Image3, { size: 16, "aria-hidden": "true" })
90481
90553
  }
90482
90554
  )
90483
90555
  }
90484
90556
  ),
90485
- /* @__PURE__ */ jsx225(Tooltip, { label: "Fit timeline to width", children: /* @__PURE__ */ jsx225(
90557
+ /* @__PURE__ */ jsx226(Tooltip, { label: "Fit timeline to width", children: /* @__PURE__ */ jsx226(
90486
90558
  "button",
90487
90559
  {
90488
90560
  type: "button",
@@ -90490,10 +90562,10 @@ function TimelineToolbar({
90490
90562
  "aria-label": "Fit timeline to width",
90491
90563
  "aria-pressed": zoomMode === "fit",
90492
90564
  className: `h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${zoomMode === "fit" ? "bg-studio-accent/10 text-studio-accent" : "text-neutral-400 hover:bg-white/6 hover:text-neutral-200"}`,
90493
- children: /* @__PURE__ */ jsx225(ArrowsOutLineHorizontal, { size: 16, "aria-hidden": "true" })
90565
+ children: /* @__PURE__ */ jsx226(ArrowsOutLineHorizontal, { size: 16, "aria-hidden": "true" })
90494
90566
  }
90495
90567
  ) }),
90496
- /* @__PURE__ */ jsx225(Tooltip, { label: "Zoom out", children: /* @__PURE__ */ jsx225(
90568
+ /* @__PURE__ */ jsx226(Tooltip, { label: "Zoom out", children: /* @__PURE__ */ jsx226(
90497
90569
  "button",
90498
90570
  {
90499
90571
  type: "button",
@@ -90505,10 +90577,10 @@ function TimelineToolbar({
90505
90577
  );
90506
90578
  },
90507
90579
  className: flatIdle,
90508
- children: /* @__PURE__ */ jsx225(MagnifyingGlassMinus, { size: 16, "aria-hidden": "true" })
90580
+ children: /* @__PURE__ */ jsx226(MagnifyingGlassMinus, { size: 16, "aria-hidden": "true" })
90509
90581
  }
90510
90582
  ) }),
90511
- /* @__PURE__ */ jsx225(
90583
+ /* @__PURE__ */ jsx226(
90512
90584
  "input",
90513
90585
  {
90514
90586
  type: "range",
@@ -90526,7 +90598,7 @@ function TimelineToolbar({
90526
90598
  className: "mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
90527
90599
  }
90528
90600
  ),
90529
- /* @__PURE__ */ jsx225(Tooltip, { label: "Zoom in", children: /* @__PURE__ */ jsx225(
90601
+ /* @__PURE__ */ jsx226(Tooltip, { label: "Zoom in", children: /* @__PURE__ */ jsx226(
90530
90602
  "button",
90531
90603
  {
90532
90604
  type: "button",
@@ -90538,10 +90610,10 @@ function TimelineToolbar({
90538
90610
  );
90539
90611
  },
90540
90612
  className: flatIdle,
90541
- children: /* @__PURE__ */ jsx225(MagnifyingGlassPlus, { size: 16, "aria-hidden": "true" })
90613
+ children: /* @__PURE__ */ jsx226(MagnifyingGlassPlus, { size: 16, "aria-hidden": "true" })
90542
90614
  }
90543
90615
  ) }),
90544
- /* @__PURE__ */ jsx225(
90616
+ /* @__PURE__ */ jsx226(
90545
90617
  "span",
90546
90618
  {
90547
90619
  className: "ml-1 w-[38px] text-right font-mono text-[11px] tabular-nums text-neutral-500 select-none",
@@ -90555,18 +90627,18 @@ function TimelineToolbar({
90555
90627
  }
90556
90628
 
90557
90629
  // src/components/StudioSplash.tsx
90558
- import { jsx as jsx226, jsxs as jsxs180 } from "react/jsx-runtime";
90630
+ import { jsx as jsx227, jsxs as jsxs181 } from "react/jsx-runtime";
90559
90631
  function StudioSplash({ waiting }) {
90560
- return /* @__PURE__ */ jsx226("div", { className: "h-full w-full bg-neutral-950 flex items-center justify-center", children: waiting ? /* @__PURE__ */ jsxs180("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
90561
- /* @__PURE__ */ jsx226("div", { className: "w-4 h-4 rounded-full border-2 border-neutral-700 border-t-neutral-500 animate-spin motion-reduce:animate-none" }),
90562
- /* @__PURE__ */ jsxs180("p", { className: "text-xs text-neutral-600", children: [
90632
+ return /* @__PURE__ */ jsx227("div", { className: "h-full w-full bg-neutral-950 flex items-center justify-center", children: waiting ? /* @__PURE__ */ jsxs181("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
90633
+ /* @__PURE__ */ jsx227("div", { className: "w-4 h-4 rounded-full border-2 border-neutral-700 border-t-neutral-500 animate-spin motion-reduce:animate-none" }),
90634
+ /* @__PURE__ */ jsxs181("p", { className: "text-xs text-neutral-600", children: [
90563
90635
  "Waiting for preview server\u2026 run",
90564
90636
  " ",
90565
- /* @__PURE__ */ jsx226("code", { className: "text-neutral-500 font-mono", children: "npm run dev" })
90637
+ /* @__PURE__ */ jsx227("code", { className: "text-neutral-500 font-mono", children: "npm run dev" })
90566
90638
  ] })
90567
- ] }) : /* @__PURE__ */ jsxs180("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
90568
- /* @__PURE__ */ jsx226("div", { className: "w-4 h-4 rounded-full bg-studio-accent animate-pulse motion-reduce:animate-none" }),
90569
- /* @__PURE__ */ jsx226("p", { className: "text-xs text-neutral-600", children: "Connecting to project\u2026" })
90639
+ ] }) : /* @__PURE__ */ jsxs181("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
90640
+ /* @__PURE__ */ jsx227("div", { className: "w-4 h-4 rounded-full bg-studio-accent animate-pulse motion-reduce:animate-none" }),
90641
+ /* @__PURE__ */ jsx227("p", { className: "text-xs text-neutral-600", children: "Connecting to project\u2026" })
90570
90642
  ] }) });
90571
90643
  }
90572
90644
 
@@ -90833,7 +90905,7 @@ function useActiveComposition({
90833
90905
  }
90834
90906
 
90835
90907
  // src/App.tsx
90836
- import { Fragment as Fragment64, jsx as jsx227, jsxs as jsxs181 } from "react/jsx-runtime";
90908
+ import { Fragment as Fragment64, jsx as jsx228, jsxs as jsxs182 } from "react/jsx-runtime";
90837
90909
  var getTimelineSelectionSet = () => usePlayerStore.getState().selectedElementIds;
90838
90910
  function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
90839
90911
  const { projectId, resolving, waitingForServer } = useServerConnection();
@@ -91197,7 +91269,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
91197
91269
  refreshPreviewDocumentVersion
91198
91270
  });
91199
91271
  const timelineToolbar = useMemo79(
91200
- () => /* @__PURE__ */ jsx227(
91272
+ () => /* @__PURE__ */ jsx228(
91201
91273
  TimelineToolbar,
91202
91274
  {
91203
91275
  domEditSession,
@@ -91207,15 +91279,15 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
91207
91279
  [domEditSession, timelineEditing.handleTimelineElementSplit]
91208
91280
  );
91209
91281
  if (resolving || waitingForServer || !projectId)
91210
- return /* @__PURE__ */ jsx227(StudioSplash, { waiting: waitingForServer });
91211
- return /* @__PURE__ */ jsx227(StudioShellProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx227(StudioPlaybackProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx227(PanelLayoutProvider, { value: layout, children: /* @__PURE__ */ jsx227(FileManagerProvider, { value: fileManager, children: /* @__PURE__ */ jsx227(DomEditProvider, { value: domEditSession, children: /* @__PURE__ */ jsxs181(
91282
+ return /* @__PURE__ */ jsx228(StudioSplash, { waiting: waitingForServer });
91283
+ return /* @__PURE__ */ jsx228(StudioShellProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx228(StudioPlaybackProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx228(PanelLayoutProvider, { value: layout, children: /* @__PURE__ */ jsx228(FileManagerProvider, { value: fileManager, children: /* @__PURE__ */ jsx228(DomEditProvider, { value: domEditSession, children: /* @__PURE__ */ jsxs182(
91212
91284
  "div",
91213
91285
  {
91214
91286
  className: "flex flex-col h-full w-full bg-neutral-950 relative",
91215
91287
  onDragOver: fileDrop.onDragOver,
91216
91288
  onDrop: fileDrop.onDrop,
91217
91289
  children: [
91218
- /* @__PURE__ */ jsx227(
91290
+ /* @__PURE__ */ jsx228(
91219
91291
  StudioHeader,
91220
91292
  {
91221
91293
  captureFrameHref: frameCapture.captureFrameHref,
@@ -91233,23 +91305,23 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
91233
91305
  }
91234
91306
  }
91235
91307
  ),
91236
- previewPersistence.domEditSaveQueuePaused && !externalFileChanges.blocked && /* @__PURE__ */ jsx227(
91308
+ previewPersistence.domEditSaveQueuePaused && !externalFileChanges.blocked && /* @__PURE__ */ jsx228(
91237
91309
  SaveQueuePausedBanner,
91238
91310
  {
91239
91311
  message: previewPersistence.domEditSaveQueuePaused,
91240
91312
  onRetry: previewPersistence.resetDomEditSaveQueueBreaker
91241
91313
  }
91242
91314
  ),
91243
- /* @__PURE__ */ jsx227(ExternalFileConflictBanner, { coordinator: externalFileChanges }),
91244
- sdkHandle.unreachableProject && /* @__PURE__ */ jsx227(ProjectUnreachableBanner, { projectId: sdkHandle.unreachableProject }),
91245
- sdkHandle.compositionMissing && activeCompPath && /* @__PURE__ */ jsx227(CompositionMissingBanner, { path: activeCompPath }),
91246
- /* @__PURE__ */ jsx227(
91315
+ /* @__PURE__ */ jsx228(ExternalFileConflictBanner, { coordinator: externalFileChanges }),
91316
+ sdkHandle.unreachableProject && /* @__PURE__ */ jsx228(ProjectUnreachableBanner, { projectId: sdkHandle.unreachableProject }),
91317
+ sdkHandle.compositionMissing && activeCompPath && /* @__PURE__ */ jsx228(CompositionMissingBanner, { path: activeCompPath }),
91318
+ /* @__PURE__ */ jsx228(
91247
91319
  EditorShell,
91248
91320
  {
91249
91321
  readOnlyPreview,
91250
91322
  readOnlyPreviewReason,
91251
- panels: /* @__PURE__ */ jsxs181(Fragment64, { children: [
91252
- /* @__PURE__ */ jsx227(
91323
+ panels: /* @__PURE__ */ jsxs182(Fragment64, { children: [
91324
+ /* @__PURE__ */ jsx228(
91253
91325
  StudioLeftPanels,
91254
91326
  {
91255
91327
  onSelectComposition: handleSelectComposition,
@@ -91264,7 +91336,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
91264
91336
  onAddCompositionToTimeline: handleAddCompositionAtPlayhead
91265
91337
  }
91266
91338
  ),
91267
- /* @__PURE__ */ jsx227(
91339
+ /* @__PURE__ */ jsx228(
91268
91340
  StudioRightPanels,
91269
91341
  {
91270
91342
  activeBlockParams,
@@ -91319,7 +91391,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
91319
91391
  recordingState: gestureState,
91320
91392
  onToggleRecording: handleToggleRecording,
91321
91393
  blockPreview,
91322
- gestureOverlay: gestureState === "recording" && previewIframe ? /* @__PURE__ */ jsx227(
91394
+ gestureOverlay: gestureState === "recording" && previewIframe ? /* @__PURE__ */ jsx228(
91323
91395
  GestureTrailOverlay,
91324
91396
  {
91325
91397
  samples: gestureRecording.samplesRef.current,
@@ -91332,7 +91404,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
91332
91404
  ) : void 0
91333
91405
  }
91334
91406
  ),
91335
- /* @__PURE__ */ jsx227(
91407
+ /* @__PURE__ */ jsx228(
91336
91408
  StudioOverlays,
91337
91409
  {
91338
91410
  projectId,